LCOV - code coverage report
Current view: top level - shared - varlink.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 827 1241 66.6 %
Date: 2019-08-23 13:36:53 Functions: 71 89 79.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 568 1180 48.1 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <sys/poll.h>
       4                 :            : 
       5                 :            : #include "alloc-util.h"
       6                 :            : #include "errno-util.h"
       7                 :            : #include "fd-util.h"
       8                 :            : #include "hashmap.h"
       9                 :            : #include "list.h"
      10                 :            : #include "process-util.h"
      11                 :            : #include "set.h"
      12                 :            : #include "socket-util.h"
      13                 :            : #include "string-table.h"
      14                 :            : #include "string-util.h"
      15                 :            : #include "strv.h"
      16                 :            : #include "time-util.h"
      17                 :            : #include "umask-util.h"
      18                 :            : #include "user-util.h"
      19                 :            : #include "varlink.h"
      20                 :            : 
      21                 :            : #define VARLINK_DEFAULT_CONNECTIONS_MAX 4096U
      22                 :            : #define VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX 1024U
      23                 :            : 
      24                 :            : #define VARLINK_DEFAULT_TIMEOUT_USEC (45U*USEC_PER_SEC)
      25                 :            : #define VARLINK_BUFFER_MAX (16U*1024U*1024U)
      26                 :            : #define VARLINK_READ_SIZE (64U*1024U)
      27                 :            : 
      28                 :            : typedef enum VarlinkState {
      29                 :            :         /* Client side states */
      30                 :            :         VARLINK_IDLE_CLIENT,
      31                 :            :         VARLINK_AWAITING_REPLY,
      32                 :            :         VARLINK_CALLING,
      33                 :            :         VARLINK_CALLED,
      34                 :            :         VARLINK_PROCESSING_REPLY,
      35                 :            : 
      36                 :            :         /* Server side states */
      37                 :            :         VARLINK_IDLE_SERVER,
      38                 :            :         VARLINK_PROCESSING_METHOD,
      39                 :            :         VARLINK_PROCESSING_METHOD_MORE,
      40                 :            :         VARLINK_PROCESSING_METHOD_ONEWAY,
      41                 :            :         VARLINK_PROCESSED_METHOD,
      42                 :            :         VARLINK_PROCESSED_METHOD_MORE,
      43                 :            :         VARLINK_PENDING_METHOD,
      44                 :            :         VARLINK_PENDING_METHOD_MORE,
      45                 :            : 
      46                 :            :         /* Common states (only during shutdown) */
      47                 :            :         VARLINK_PENDING_DISCONNECT,
      48                 :            :         VARLINK_PENDING_TIMEOUT,
      49                 :            :         VARLINK_PROCESSING_DISCONNECT,
      50                 :            :         VARLINK_PROCESSING_TIMEOUT,
      51                 :            :         VARLINK_PROCESSING_FAILURE,
      52                 :            :         VARLINK_DISCONNECTED,
      53                 :            : 
      54                 :            :         _VARLINK_STATE_MAX,
      55                 :            :         _VARLINK_STATE_INVALID = -1
      56                 :            : } VarlinkState;
      57                 :            : 
      58                 :            : /* Tests whether we are not yet disconnected. Note that this is true during all states where the connection
      59                 :            :  * is still good for something, and false only when it's dead for good. This means: when we are
      60                 :            :  * asynchronously connecting to a peer and the connect() is still pending, then this will return 'true', as
      61                 :            :  * the connection is still good, and we are likely to be able to properly operate on it soon. */
      62                 :            : #define VARLINK_STATE_IS_ALIVE(state)                   \
      63                 :            :         IN_SET(state,                                   \
      64                 :            :                VARLINK_IDLE_CLIENT,                     \
      65                 :            :                VARLINK_AWAITING_REPLY,                  \
      66                 :            :                VARLINK_CALLING,                         \
      67                 :            :                VARLINK_CALLED,                          \
      68                 :            :                VARLINK_PROCESSING_REPLY,                \
      69                 :            :                VARLINK_IDLE_SERVER,                     \
      70                 :            :                VARLINK_PROCESSING_METHOD,               \
      71                 :            :                VARLINK_PROCESSING_METHOD_MORE,          \
      72                 :            :                VARLINK_PROCESSING_METHOD_ONEWAY,        \
      73                 :            :                VARLINK_PROCESSED_METHOD,                \
      74                 :            :                VARLINK_PROCESSED_METHOD_MORE,           \
      75                 :            :                VARLINK_PENDING_METHOD,                  \
      76                 :            :                VARLINK_PENDING_METHOD_MORE)
      77                 :            : 
      78                 :            : struct Varlink {
      79                 :            :         unsigned n_ref;
      80                 :            : 
      81                 :            :         VarlinkServer *server;
      82                 :            : 
      83                 :            :         VarlinkState state;
      84                 :            :         bool connecting; /* This boolean indicates whether the socket fd we are operating on is currently
      85                 :            :                           * processing an asynchronous connect(). In that state we watch the socket for
      86                 :            :                           * EPOLLOUT, but we refrain from calling read() or write() on the socket as that
      87                 :            :                           * will trigger ENOTCONN. Note that this boolean is kept separate from the
      88                 :            :                           * VarlinkState above on purpose: while the connect() is still not complete we
      89                 :            :                           * already want to allow queuing of messages and similar. Thus it's nice to keep
      90                 :            :                           * these two state concepts separate: the VarlinkState encodes what our own view of
      91                 :            :                           * the connection is, i.e. whether we think it's a server, a client, and has
      92                 :            :                           * something queued already, while 'connecting' tells us a detail about the
      93                 :            :                           * transport used below, that should have no effect on how we otherwise accept and
      94                 :            :                           * process operations from the user.
      95                 :            :                           *
      96                 :            :                           * Or to say this differently: VARLINK_STATE_IS_ALIVE(state) tells you whether the
      97                 :            :                           * connection is good to use, even if it might not be fully connected
      98                 :            :                           * yet. connecting=true then informs you that actually we are still connecting, and
      99                 :            :                           * the connection is actually not established yet and thus any requests you enqueue
     100                 :            :                           * now will still work fine but will be queued only, not sent yet, but that
     101                 :            :                           * shouldn't stop you from using the connection, since eventually whatever you queue
     102                 :            :                           * *will* be sent.
     103                 :            :                           *
     104                 :            :                           * Or to say this even differently: 'state' is a high-level ("application layer"
     105                 :            :                           * high, if you so will) state, while 'conecting' is a low-level ("transport layer"
     106                 :            :                           * low, if you so will) state, and while they are not entirely unrelated and
     107                 :            :                           * sometimes propagate effects to each other they are only asynchronously connected
     108                 :            :                           * at most. */
     109                 :            :         unsigned n_pending;
     110                 :            : 
     111                 :            :         int fd;
     112                 :            : 
     113                 :            :         char *input_buffer; /* valid data starts at input_buffer_index, ends at input_buffer_index+input_buffer_size */
     114                 :            :         size_t input_buffer_allocated;
     115                 :            :         size_t input_buffer_index;
     116                 :            :         size_t input_buffer_size;
     117                 :            :         size_t input_buffer_unscanned;
     118                 :            : 
     119                 :            :         char *output_buffer; /* valid data starts at output_buffer_index, ends at output_buffer_index+output_buffer_size */
     120                 :            :         size_t output_buffer_allocated;
     121                 :            :         size_t output_buffer_index;
     122                 :            :         size_t output_buffer_size;
     123                 :            : 
     124                 :            :         VarlinkReply reply_callback;
     125                 :            : 
     126                 :            :         JsonVariant *current;
     127                 :            :         JsonVariant *reply;
     128                 :            : 
     129                 :            :         struct ucred ucred;
     130                 :            :         bool ucred_acquired:1;
     131                 :            : 
     132                 :            :         bool write_disconnected:1;
     133                 :            :         bool read_disconnected:1;
     134                 :            :         bool prefer_read_write:1;
     135                 :            :         bool got_pollhup:1;
     136                 :            : 
     137                 :            :         usec_t timestamp;
     138                 :            :         usec_t timeout;
     139                 :            : 
     140                 :            :         void *userdata;
     141                 :            :         char *description;
     142                 :            : 
     143                 :            :         sd_event *event;
     144                 :            :         sd_event_source *io_event_source;
     145                 :            :         sd_event_source *time_event_source;
     146                 :            :         sd_event_source *quit_event_source;
     147                 :            :         sd_event_source *defer_event_source;
     148                 :            : };
     149                 :            : 
     150                 :            : typedef struct VarlinkServerSocket VarlinkServerSocket;
     151                 :            : 
     152                 :            : struct VarlinkServerSocket {
     153                 :            :         VarlinkServer *server;
     154                 :            : 
     155                 :            :         int fd;
     156                 :            :         char *address;
     157                 :            : 
     158                 :            :         sd_event_source *event_source;
     159                 :            : 
     160                 :            :         LIST_FIELDS(VarlinkServerSocket, sockets);
     161                 :            : };
     162                 :            : 
     163                 :            : struct VarlinkServer {
     164                 :            :         unsigned n_ref;
     165                 :            :         VarlinkServerFlags flags;
     166                 :            : 
     167                 :            :         LIST_HEAD(VarlinkServerSocket, sockets);
     168                 :            : 
     169                 :            :         Hashmap *methods;
     170                 :            :         VarlinkConnect connect_callback;
     171                 :            : 
     172                 :            :         sd_event *event;
     173                 :            :         int64_t event_priority;
     174                 :            : 
     175                 :            :         unsigned n_connections;
     176                 :            :         Hashmap *by_uid;
     177                 :            : 
     178                 :            :         void *userdata;
     179                 :            :         char *description;
     180                 :            : 
     181                 :            :         unsigned connections_max;
     182                 :            :         unsigned connections_per_uid_max;
     183                 :            : };
     184                 :            : 
     185                 :            : static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
     186                 :            :         [VARLINK_IDLE_CLIENT]              = "idle-client",
     187                 :            :         [VARLINK_AWAITING_REPLY]           = "awaiting-reply",
     188                 :            :         [VARLINK_CALLING]                  = "calling",
     189                 :            :         [VARLINK_CALLED]                   = "called",
     190                 :            :         [VARLINK_PROCESSING_REPLY]         = "processing-reply",
     191                 :            :         [VARLINK_IDLE_SERVER]              = "idle-server",
     192                 :            :         [VARLINK_PROCESSING_METHOD]        = "processing-method",
     193                 :            :         [VARLINK_PROCESSING_METHOD_MORE]   = "processing-method-more",
     194                 :            :         [VARLINK_PROCESSING_METHOD_ONEWAY] = "processing-method-oneway",
     195                 :            :         [VARLINK_PROCESSED_METHOD]         = "processed-method",
     196                 :            :         [VARLINK_PROCESSED_METHOD_MORE]    = "processed-method-more",
     197                 :            :         [VARLINK_PENDING_METHOD]           = "pending-method",
     198                 :            :         [VARLINK_PENDING_METHOD_MORE]      = "pending-method-more",
     199                 :            :         [VARLINK_PENDING_DISCONNECT]       = "pending-disconnect",
     200                 :            :         [VARLINK_PENDING_TIMEOUT]          = "pending-timeout",
     201                 :            :         [VARLINK_PROCESSING_DISCONNECT]    = "processing-disconnect",
     202                 :            :         [VARLINK_PROCESSING_TIMEOUT]       = "processing-timeout",
     203                 :            :         [VARLINK_PROCESSING_FAILURE]       = "processing-failure",
     204                 :            :         [VARLINK_DISCONNECTED]             = "disconnected",
     205                 :            : };
     206                 :            : 
     207   [ +  -  -  + ]:      12240 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(varlink_state, VarlinkState);
     208                 :            : 
     209                 :            : #define varlink_log_errno(v, error, fmt, ...)                           \
     210                 :            :         log_debug_errno(error, "%s: " fmt, varlink_description(v), ##__VA_ARGS__)
     211                 :            : 
     212                 :            : #define varlink_log(v, fmt, ...)                                        \
     213                 :            :         log_debug("%s: " fmt, varlink_description(v), ##__VA_ARGS__)
     214                 :            : 
     215                 :            : #define varlink_server_log_errno(s, error, fmt, ...) \
     216                 :            :         log_debug_errno(error, "%s: " fmt, varlink_server_description(s), ##__VA_ARGS__)
     217                 :            : 
     218                 :            : #define varlink_server_log(s, fmt, ...) \
     219                 :            :         log_debug("%s: " fmt, varlink_server_description(s), ##__VA_ARGS__)
     220                 :            : 
     221                 :      10067 : static inline const char *varlink_description(Varlink *v) {
     222         [ +  - ]:      10067 :         return strna(v ? v->description : NULL);
     223                 :            : }
     224                 :            : 
     225                 :       1048 : static inline const char *varlink_server_description(VarlinkServer *s) {
     226         [ +  - ]:       1048 :         return strna(s ? s->description : NULL);
     227                 :            : }
     228                 :            : 
     229                 :       7054 : static void varlink_set_state(Varlink *v, VarlinkState state) {
     230         [ -  + ]:       7054 :         assert(v);
     231   [ +  -  -  + ]:       7054 :         assert(state >= 0 && state < _VARLINK_STATE_MAX);
     232                 :            : 
     233         [ +  + ]:       7054 :         if (v->state < 0)
     234         [ +  - ]:       1868 :                 varlink_log(v, "varlink: setting state %s",
     235                 :            :                             varlink_state_to_string(state));
     236                 :            :         else
     237         [ +  - ]:       5186 :                 varlink_log(v, "varlink: changing state %s → %s",
     238                 :            :                             varlink_state_to_string(v->state),
     239                 :            :                             varlink_state_to_string(state));
     240                 :            : 
     241                 :       7054 :         v->state = state;
     242                 :       7054 : }
     243                 :            : 
     244                 :       1868 : static int varlink_new(Varlink **ret) {
     245                 :            :         Varlink *v;
     246                 :            : 
     247         [ -  + ]:       1868 :         assert(ret);
     248                 :            : 
     249                 :       1868 :         v = new(Varlink, 1);
     250         [ -  + ]:       1868 :         if (!v)
     251                 :          0 :                 return -ENOMEM;
     252                 :            : 
     253                 :       1868 :         *v = (Varlink) {
     254                 :            :                 .n_ref = 1,
     255                 :            :                 .fd = -1,
     256                 :            : 
     257                 :            :                 .state = _VARLINK_STATE_INVALID,
     258                 :            : 
     259                 :            :                 .ucred.uid = UID_INVALID,
     260                 :            :                 .ucred.gid = GID_INVALID,
     261                 :            : 
     262                 :            :                 .timestamp = USEC_INFINITY,
     263                 :            :                 .timeout = VARLINK_DEFAULT_TIMEOUT_USEC
     264                 :            :         };
     265                 :            : 
     266                 :       1868 :         *ret = v;
     267                 :       1868 :         return 0;
     268                 :            : }
     269                 :            : 
     270                 :       1344 : int varlink_connect_address(Varlink **ret, const char *address) {
     271                 :       1344 :         _cleanup_(varlink_unrefp) Varlink *v = NULL;
     272                 :            :         union sockaddr_union sockaddr;
     273                 :            :         int r;
     274                 :            : 
     275   [ -  +  -  + ]:       1344 :         assert_return(ret, -EINVAL);
     276   [ -  +  -  + ]:       1344 :         assert_return(address, -EINVAL);
     277                 :            : 
     278                 :       1344 :         r = sockaddr_un_set_path(&sockaddr.un, address);
     279         [ -  + ]:       1344 :         if (r < 0)
     280                 :          0 :                 return r;
     281                 :            : 
     282                 :       1344 :         r = varlink_new(&v);
     283         [ -  + ]:       1344 :         if (r < 0)
     284                 :          0 :                 return r;
     285                 :            : 
     286                 :       1344 :         v->fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
     287         [ -  + ]:       1344 :         if (v->fd < 0)
     288                 :          0 :                 return -errno;
     289                 :            : 
     290   [ -  +  -  +  :       1344 :         if (connect(v->fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) {
                   +  + ]
     291   [ +  -  -  + ]:        820 :                 if (!IN_SET(errno, EAGAIN, EINPROGRESS))
     292                 :          0 :                         return -errno;
     293                 :            : 
     294                 :        820 :                 v->connecting = true; /* We are asynchronously connecting, i.e. the connect() is being
     295                 :            :                                        * processed in the background. As long as that's the case the socket
     296                 :            :                                        * is in a special state: it's there, we can poll it for EPOLLOUT, but
     297                 :            :                                        * if we attempt to write() to it before we see EPOLLOUT we'll get
     298                 :            :                                        * ENOTCONN (and not EAGAIN, like we would for a normal connected
     299                 :            :                                        * socket that isn't writable at the moment). Since ENOTCONN on write()
     300                 :            :                                        * hence can mean two different things (i.e. connection not complete
     301                 :            :                                        * yet vs. already disconnected again), we store as a boolean whether
     302                 :            :                                        * we are still in connect(). */
     303                 :            :         }
     304                 :            : 
     305                 :       1344 :         varlink_set_state(v, VARLINK_IDLE_CLIENT);
     306                 :            : 
     307                 :       1344 :         *ret = TAKE_PTR(v);
     308                 :       1344 :         return r;
     309                 :            : }
     310                 :            : 
     311                 :          0 : int varlink_connect_fd(Varlink **ret, int fd) {
     312                 :            :         Varlink *v;
     313                 :            :         int r;
     314                 :            : 
     315   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     316   [ #  #  #  # ]:          0 :         assert_return(fd >= 0, -EBADF);
     317                 :            : 
     318                 :          0 :         r = fd_nonblock(fd, true);
     319         [ #  # ]:          0 :         if (r < 0)
     320                 :          0 :                 return r;
     321                 :            : 
     322                 :          0 :         r = varlink_new(&v);
     323         [ #  # ]:          0 :         if (r < 0)
     324                 :          0 :                 return r;
     325                 :            : 
     326                 :          0 :         v->fd = fd;
     327                 :          0 :         varlink_set_state(v, VARLINK_IDLE_CLIENT);
     328                 :            : 
     329                 :            :         /* Note that if this function is called we assume the passed socket (if it is one) is already
     330                 :            :          * properly connected, i.e. any asynchronous connect() done on it already completed. Because of that
     331                 :            :          * we'll not set the 'connecting' boolean here, i.e. we don't need to avoid write()ing to the socket
     332                 :            :          * until the connection is fully set up. Behaviour here is hence a bit different from
     333                 :            :          * varlink_connect_address() above, as there we do handle asynchronous connections ourselves and
     334                 :            :          * avoid doing write() on it before we saw EPOLLOUT for the first time. */
     335                 :            : 
     336                 :          0 :         *ret = v;
     337                 :          0 :         return 0;
     338                 :            : }
     339                 :            : 
     340                 :       3736 : static void varlink_detach_event_sources(Varlink *v) {
     341         [ -  + ]:       3736 :         assert(v);
     342                 :            : 
     343                 :       3736 :         v->io_event_source = sd_event_source_disable_unref(v->io_event_source);
     344                 :            : 
     345                 :       3736 :         v->time_event_source = sd_event_source_disable_unref(v->time_event_source);
     346                 :            : 
     347                 :       3736 :         v->quit_event_source = sd_event_source_disable_unref(v->quit_event_source);
     348                 :            : 
     349                 :       3736 :         v->defer_event_source = sd_event_source_disable_unref(v->defer_event_source);
     350                 :       3736 : }
     351                 :            : 
     352                 :       3736 : static void varlink_clear(Varlink *v) {
     353         [ -  + ]:       3736 :         assert(v);
     354                 :            : 
     355                 :       3736 :         varlink_detach_event_sources(v);
     356                 :            : 
     357                 :       3736 :         v->fd = safe_close(v->fd);
     358                 :            : 
     359                 :       3736 :         v->input_buffer = mfree(v->input_buffer);
     360                 :       3736 :         v->output_buffer = mfree(v->output_buffer);
     361                 :            : 
     362                 :       3736 :         v->current = json_variant_unref(v->current);
     363                 :       3736 :         v->reply = json_variant_unref(v->reply);
     364                 :            : 
     365                 :       3736 :         v->event = sd_event_unref(v->event);
     366                 :       3736 : }
     367                 :            : 
     368                 :       1868 : static Varlink* varlink_destroy(Varlink *v) {
     369         [ -  + ]:       1868 :         if (!v)
     370                 :          0 :                 return NULL;
     371                 :            : 
     372                 :            :         /* If this is called the server object must already been unreffed here. Why that? because when we
     373                 :            :          * linked up the varlink connection with the server object we took one ref in each direction */
     374         [ -  + ]:       1868 :         assert(!v->server);
     375                 :            : 
     376                 :       1868 :         varlink_clear(v);
     377                 :            : 
     378                 :       1868 :         free(v->description);
     379                 :       1868 :         return mfree(v);
     380                 :            : }
     381                 :            : 
     382   [ -  +  -  +  :      21362 : DEFINE_TRIVIAL_REF_UNREF_FUNC(Varlink, varlink, varlink_destroy);
                   +  + ]
     383                 :            : 
     384                 :       4594 : static int varlink_test_disconnect(Varlink *v) {
     385         [ -  + ]:       4594 :         assert(v);
     386                 :            : 
     387                 :            :         /* Tests whether we the the connection has been terminated. We are careful to not stop processing it
     388                 :            :          * prematurely, since we want to handle half-open connections as well as possible and want to flush
     389                 :            :          * out and read data before we close down if we can. */
     390                 :            : 
     391                 :            :         /* Already disconnected? */
     392   [ +  +  +  + ]:       4594 :         if (!VARLINK_STATE_IS_ALIVE(v->state))
     393                 :       1101 :                 return 0;
     394                 :            : 
     395                 :            :         /* Wait until connection setup is complete, i.e. until asynchronous connect() completes */
     396         [ +  + ]:       3493 :         if (v->connecting)
     397                 :        820 :                 return 0;
     398                 :            : 
     399                 :            :         /* Still something to write and we can write? Stay around */
     400   [ +  +  -  + ]:       2673 :         if (v->output_buffer_size > 0 && !v->write_disconnected)
     401                 :          0 :                 return 0;
     402                 :            : 
     403                 :            :         /* Both sides gone already? Then there's no need to stick around */
     404   [ +  +  -  + ]:       2673 :         if (v->read_disconnected && v->write_disconnected)
     405                 :          0 :                 goto disconnect;
     406                 :            : 
     407                 :            :         /* If we are waiting for incoming data but the read side is shut down, disconnect. */
     408   [ +  +  +  +  :       2673 :         if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) && v->read_disconnected)
                   +  + ]
     409                 :        281 :                 goto disconnect;
     410                 :            : 
     411                 :            :         /* Similar, if are a client that hasn't written anything yet but the write side is dead, also
     412                 :            :          * disconnect. We also explicitly check for POLLHUP here since we likely won't notice the write side
     413                 :            :          * being down if we never wrote anything. */
     414   [ +  +  +  +  :       2392 :         if (IN_SET(v->state, VARLINK_IDLE_CLIENT) && (v->write_disconnected || v->got_pollhup))
             +  +  -  + ]
     415                 :        816 :                 goto disconnect;
     416                 :            : 
     417                 :       1576 :         return 0;
     418                 :            : 
     419                 :       1097 : disconnect:
     420                 :       1097 :         varlink_set_state(v, VARLINK_PENDING_DISCONNECT);
     421                 :       1097 :         return 1;
     422                 :            : }
     423                 :            : 
     424                 :       7359 : static int varlink_write(Varlink *v) {
     425                 :            :         ssize_t n;
     426                 :            : 
     427         [ -  + ]:       7359 :         assert(v);
     428                 :            : 
     429   [ +  +  +  + ]:       7359 :         if (!VARLINK_STATE_IS_ALIVE(v->state))
     430                 :       1101 :                 return 0;
     431         [ +  + ]:       6258 :         if (v->connecting) /* Writing while we are still wait for a non-blocking connect() to complete will
     432                 :            :                             * result in ENOTCONN, hence exit early here */
     433                 :        820 :                 return 0;
     434         [ +  + ]:       5438 :         if (v->output_buffer_size == 0)
     435                 :       3254 :                 return 0;
     436         [ +  + ]:       2184 :         if (v->write_disconnected)
     437                 :        820 :                 return 0;
     438                 :            : 
     439         [ -  + ]:       1364 :         assert(v->fd >= 0);
     440                 :            : 
     441                 :            :         /* We generally prefer recv()/send() (mostly because of MSG_NOSIGNAL) but also want to be compatible
     442                 :            :          * with non-socket IO, hence fall back automatically */
     443         [ +  - ]:       1364 :         if (!v->prefer_read_write) {
     444                 :       1364 :                 n = send(v->fd, v->output_buffer + v->output_buffer_index, v->output_buffer_size, MSG_DONTWAIT|MSG_NOSIGNAL);
     445   [ +  +  -  + ]:       1364 :                 if (n < 0 && errno == ENOTSOCK)
     446                 :          0 :                         v->prefer_read_write = true;
     447                 :            :         }
     448         [ -  + ]:       1364 :         if (v->prefer_read_write)
     449                 :          0 :                 n = write(v->fd, v->output_buffer + v->output_buffer_index, v->output_buffer_size);
     450         [ +  + ]:       1364 :         if (n < 0) {
     451         [ -  + ]:        820 :                 if (errno == EAGAIN)
     452                 :          0 :                         return 0;
     453                 :            : 
     454         [ +  - ]:        820 :                 if (ERRNO_IS_DISCONNECT(errno)) {
     455                 :            :                         /* If we get informed about a disconnect on write, then let's remember that, but not
     456                 :            :                          * act on it just yet. Let's wait for read() to report the issue first. */
     457                 :        820 :                         v->write_disconnected = true;
     458                 :        820 :                         return 1;
     459                 :            :                 }
     460                 :            : 
     461                 :          0 :                 return -errno;
     462                 :            :         }
     463                 :            : 
     464                 :        544 :         v->output_buffer_size -= n;
     465                 :            : 
     466         [ +  - ]:        544 :         if (v->output_buffer_size == 0)
     467                 :        544 :                 v->output_buffer_index = 0;
     468                 :            :         else
     469                 :          0 :                 v->output_buffer_index += n;
     470                 :            : 
     471                 :        544 :         v->timestamp = now(CLOCK_MONOTONIC);
     472                 :        544 :         return 1;
     473                 :            : }
     474                 :            : 
     475                 :       5427 : static int varlink_read(Varlink *v) {
     476                 :            :         size_t rs;
     477                 :            :         ssize_t n;
     478                 :            : 
     479         [ -  + ]:       5427 :         assert(v);
     480                 :            : 
     481   [ +  +  +  + ]:       5427 :         if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER))
     482                 :       3253 :                 return 0;
     483         [ +  + ]:       2174 :         if (v->connecting) /* read() on a socket while we are in connect() will fail with EINVAL, hence exit early here */
     484                 :          4 :                 return 0;
     485         [ -  + ]:       2170 :         if (v->current)
     486                 :          0 :                 return 0;
     487         [ -  + ]:       2170 :         if (v->input_buffer_unscanned > 0)
     488                 :          0 :                 return 0;
     489         [ +  + ]:       2170 :         if (v->read_disconnected)
     490                 :        281 :                 return 0;
     491                 :            : 
     492         [ -  + ]:       1889 :         if (v->input_buffer_size >= VARLINK_BUFFER_MAX)
     493                 :          0 :                 return -ENOBUFS;
     494                 :            : 
     495         [ -  + ]:       1889 :         assert(v->fd >= 0);
     496                 :            : 
     497         [ +  + ]:       1889 :         if (v->input_buffer_allocated <= v->input_buffer_index + v->input_buffer_size) {
     498                 :            :                 size_t add;
     499                 :            : 
     500                 :        536 :                 add = MIN(VARLINK_BUFFER_MAX - v->input_buffer_size, VARLINK_READ_SIZE);
     501                 :            : 
     502         [ +  - ]:        536 :                 if (v->input_buffer_index == 0) {
     503                 :            : 
     504         [ -  + ]:        536 :                         if (!GREEDY_REALLOC(v->input_buffer, v->input_buffer_allocated, v->input_buffer_size + add))
     505                 :          0 :                                 return -ENOMEM;
     506                 :            : 
     507                 :            :                 } else {
     508                 :            :                         char *b;
     509                 :            : 
     510                 :          0 :                         b = new(char, v->input_buffer_size + add);
     511         [ #  # ]:          0 :                         if (!b)
     512                 :          0 :                                 return -ENOMEM;
     513                 :            : 
     514                 :          0 :                         memcpy(b, v->input_buffer + v->input_buffer_index, v->input_buffer_size);
     515                 :            : 
     516                 :          0 :                         free_and_replace(v->input_buffer, b);
     517                 :            : 
     518                 :          0 :                         v->input_buffer_allocated = v->input_buffer_size + add;
     519                 :          0 :                         v->input_buffer_index = 0;
     520                 :            :                 }
     521                 :            :         }
     522                 :            : 
     523                 :       1889 :         rs = v->input_buffer_allocated - (v->input_buffer_index + v->input_buffer_size);
     524                 :            : 
     525         [ +  - ]:       1889 :         if (!v->prefer_read_write) {
     526                 :       1889 :                 n = recv(v->fd, v->input_buffer + v->input_buffer_index + v->input_buffer_size, rs, MSG_DONTWAIT);
     527   [ +  +  -  + ]:       1889 :                 if (n < 0 && errno == ENOTSOCK)
     528                 :          0 :                         v->prefer_read_write = true;
     529                 :            :         }
     530         [ -  + ]:       1889 :         if (v->prefer_read_write)
     531                 :          0 :                 n = read(v->fd, v->input_buffer + v->input_buffer_index + v->input_buffer_size, rs);
     532         [ +  + ]:       1889 :         if (n < 0) {
     533         [ +  + ]:       1060 :                 if (errno == EAGAIN)
     534                 :       1056 :                         return 0;
     535                 :            : 
     536         [ -  + ]:          4 :                 if (ERRNO_IS_DISCONNECT(errno)) {
     537                 :          0 :                         v->read_disconnected = true;
     538                 :          0 :                         return 1;
     539                 :            :                 }
     540                 :            : 
     541                 :          4 :                 return -errno;
     542                 :            :         }
     543         [ +  + ]:        829 :         if (n == 0) { /* EOF */
     544                 :        285 :                 v->read_disconnected = true;
     545                 :        285 :                 return 1;
     546                 :            :         }
     547                 :            : 
     548                 :        544 :         v->input_buffer_size += n;
     549                 :        544 :         v->input_buffer_unscanned += n;
     550                 :            : 
     551                 :        544 :         return 1;
     552                 :            : }
     553                 :            : 
     554                 :       5971 : static int varlink_parse_message(Varlink *v) {
     555                 :            :         const char *e, *begin;
     556                 :            :         size_t sz;
     557                 :            :         int r;
     558                 :            : 
     559         [ -  + ]:       5971 :         assert(v);
     560                 :            : 
     561         [ -  + ]:       5971 :         if (v->current)
     562                 :          0 :                 return 0;
     563         [ +  + ]:       5971 :         if (v->input_buffer_unscanned <= 0)
     564                 :       5427 :                 return 0;
     565                 :            : 
     566         [ -  + ]:        544 :         assert(v->input_buffer_unscanned <= v->input_buffer_size);
     567         [ -  + ]:        544 :         assert(v->input_buffer_index + v->input_buffer_size <= v->input_buffer_allocated);
     568                 :            : 
     569                 :        544 :         begin = v->input_buffer + v->input_buffer_index;
     570                 :            : 
     571                 :        544 :         e = memchr(begin + v->input_buffer_size - v->input_buffer_unscanned, 0, v->input_buffer_unscanned);
     572         [ -  + ]:        544 :         if (!e) {
     573                 :          0 :                 v->input_buffer_unscanned = 0;
     574                 :          0 :                 return 0;
     575                 :            :         }
     576                 :            : 
     577                 :        544 :         sz = e - begin + 1;
     578                 :            : 
     579         [ +  - ]:        544 :         varlink_log(v, "New incoming message: %s", begin);
     580                 :            : 
     581                 :        544 :         r = json_parse(begin, &v->current, NULL, NULL);
     582         [ -  + ]:        544 :         if (r < 0)
     583                 :          0 :                 return r;
     584                 :            : 
     585                 :        544 :         v->input_buffer_size -= sz;
     586                 :            : 
     587         [ +  - ]:        544 :         if (v->input_buffer_size == 0)
     588                 :        544 :                 v->input_buffer_index = 0;
     589                 :            :         else
     590                 :          0 :                 v->input_buffer_index += sz;
     591                 :            : 
     592                 :        544 :         v->input_buffer_unscanned = v->input_buffer_size;
     593                 :        544 :         return 1;
     594                 :            : }
     595                 :            : 
     596                 :       2396 : static int varlink_test_timeout(Varlink *v) {
     597         [ -  + ]:       2396 :         assert(v);
     598                 :            : 
     599   [ +  +  +  + ]:       2396 :         if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING))
     600                 :       2380 :                 return 0;
     601         [ -  + ]:         16 :         if (v->timeout == USEC_INFINITY)
     602                 :          0 :                 return 0;
     603                 :            : 
     604         [ +  - ]:         16 :         if (now(CLOCK_MONOTONIC) < usec_add(v->timestamp, v->timeout))
     605                 :         16 :                 return 0;
     606                 :            : 
     607                 :          0 :         varlink_set_state(v, VARLINK_PENDING_TIMEOUT);
     608                 :            : 
     609                 :          0 :         return 1;
     610                 :            : }
     611                 :            : 
     612                 :       1101 : static int varlink_dispatch_local_error(Varlink *v, const char *error) {
     613                 :            :         int r;
     614                 :            : 
     615         [ -  + ]:       1101 :         assert(v);
     616         [ -  + ]:       1101 :         assert(error);
     617                 :            : 
     618         [ +  + ]:       1101 :         if (!v->reply_callback)
     619                 :       1097 :                 return 0;
     620                 :            : 
     621                 :          4 :         r = v->reply_callback(v, NULL, error, VARLINK_REPLY_ERROR|VARLINK_REPLY_LOCAL, v->userdata);
     622         [ -  + ]:          4 :         if (r < 0)
     623         [ #  # ]:          0 :                 log_debug_errno(r, "Reply callback returned error, ignoring: %m");
     624                 :            : 
     625                 :          4 :         return 1;
     626                 :            : }
     627                 :            : 
     628                 :       2396 : static int varlink_dispatch_timeout(Varlink *v) {
     629         [ -  + ]:       2396 :         assert(v);
     630                 :            : 
     631         [ +  - ]:       2396 :         if (v->state != VARLINK_PENDING_TIMEOUT)
     632                 :       2396 :                 return 0;
     633                 :            : 
     634                 :          0 :         varlink_set_state(v, VARLINK_PROCESSING_TIMEOUT);
     635                 :          0 :         varlink_dispatch_local_error(v, VARLINK_ERROR_TIMEOUT);
     636                 :          0 :         varlink_close(v);
     637                 :            : 
     638                 :          0 :         return 1;
     639                 :            : }
     640                 :            : 
     641                 :       3497 : static int varlink_dispatch_disconnect(Varlink *v) {
     642         [ -  + ]:       3497 :         assert(v);
     643                 :            : 
     644         [ +  + ]:       3497 :         if (v->state != VARLINK_PENDING_DISCONNECT)
     645                 :       2396 :                 return 0;
     646                 :            : 
     647                 :       1101 :         varlink_set_state(v, VARLINK_PROCESSING_DISCONNECT);
     648                 :       1101 :         varlink_dispatch_local_error(v, VARLINK_ERROR_DISCONNECTED);
     649                 :       1101 :         varlink_close(v);
     650                 :            : 
     651                 :       1101 :         return 1;
     652                 :            : }
     653                 :            : 
     654                 :       1908 : static int varlink_sanitize_parameters(JsonVariant **v) {
     655         [ -  + ]:       1908 :         assert(v);
     656                 :            : 
     657                 :            :         /* Varlink always wants a parameters list, hence make one if the caller doesn't want any */
     658         [ +  + ]:       1908 :         if (!*v)
     659                 :          4 :                 return json_variant_new_object(v, NULL, 0);
     660         [ -  + ]:       1904 :         else if (!json_variant_is_object(*v))
     661                 :          0 :                 return -EINVAL;
     662                 :            : 
     663                 :       1904 :         return 0;
     664                 :            : }
     665                 :            : 
     666                 :       5995 : static int varlink_dispatch_reply(Varlink *v) {
     667                 :       5995 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
     668                 :       5995 :         VarlinkReplyFlags flags = 0;
     669                 :       5995 :         const char *error = NULL;
     670                 :            :         JsonVariant *e;
     671                 :            :         const char *k;
     672                 :            :         int r;
     673                 :            : 
     674         [ -  + ]:       5995 :         assert(v);
     675                 :            : 
     676   [ +  +  +  + ]:       5995 :         if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING))
     677                 :       5939 :                 return 0;
     678         [ +  + ]:         56 :         if (!v->current)
     679                 :         44 :                 return 0;
     680                 :            : 
     681         [ -  + ]:         12 :         assert(v->n_pending > 0);
     682                 :            : 
     683         [ -  + ]:         12 :         if (!json_variant_is_object(v->current))
     684                 :          0 :                 goto invalid;
     685                 :            : 
     686   [ +  -  +  +  :         28 :         JSON_VARIANT_OBJECT_FOREACH(k, e, v->current) {
                   +  - ]
     687                 :            : 
     688         [ +  + ]:         16 :                 if (streq(k, "error")) {
     689         [ -  + ]:          4 :                         if (error)
     690                 :          0 :                                 goto invalid;
     691         [ -  + ]:          4 :                         if (!json_variant_is_string(e))
     692                 :          0 :                                 goto invalid;
     693                 :            : 
     694                 :          4 :                         error = json_variant_string(e);
     695                 :          4 :                         flags |= VARLINK_REPLY_ERROR;
     696                 :            : 
     697         [ +  - ]:         12 :                 } else if (streq(k, "parameters")) {
     698         [ -  + ]:         12 :                         if (parameters)
     699                 :          0 :                                 goto invalid;
     700         [ -  + ]:         12 :                         if (!json_variant_is_object(e))
     701                 :          0 :                                 goto invalid;
     702                 :            : 
     703                 :         12 :                         parameters = json_variant_ref(e);
     704                 :            : 
     705         [ #  # ]:          0 :                 } else if (streq(k, "continues")) {
     706         [ #  # ]:          0 :                         if (FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
     707                 :          0 :                                 goto invalid;
     708                 :            : 
     709         [ #  # ]:          0 :                         if (!json_variant_is_boolean(e))
     710                 :          0 :                                 goto invalid;
     711                 :            : 
     712         [ #  # ]:          0 :                         if (json_variant_boolean(e))
     713                 :          0 :                                 flags |= VARLINK_REPLY_CONTINUES;
     714                 :            :                 } else
     715                 :          0 :                         goto invalid;
     716                 :            :         }
     717                 :            : 
     718   [ +  +  -  + ]:         12 :         if (error && FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
     719                 :          0 :                 goto invalid;
     720                 :            : 
     721                 :         12 :         r = varlink_sanitize_parameters(&parameters);
     722         [ -  + ]:         12 :         if (r < 0)
     723                 :          0 :                 goto invalid;
     724                 :            : 
     725         [ +  + ]:         12 :         if (v->state == VARLINK_AWAITING_REPLY) {
     726                 :          4 :                 varlink_set_state(v, VARLINK_PROCESSING_REPLY);
     727                 :            : 
     728         [ +  - ]:          4 :                 if (v->reply_callback) {
     729                 :          4 :                         r = v->reply_callback(v, parameters, error, flags, v->userdata);
     730         [ -  + ]:          4 :                         if (r < 0)
     731         [ #  # ]:          0 :                                 log_debug_errno(r, "Reply callback returned error, ignoring: %m");
     732                 :            :                 }
     733                 :            : 
     734                 :          4 :                 v->current = json_variant_unref(v->current);
     735                 :            : 
     736         [ +  - ]:          4 :                 if (v->state == VARLINK_PROCESSING_REPLY) {
     737         [ -  + ]:          4 :                         assert(v->n_pending > 0);
     738                 :          4 :                         v->n_pending--;
     739                 :            : 
     740                 :          4 :                         varlink_set_state(v, v->n_pending == 0 ? VARLINK_IDLE_CLIENT : VARLINK_AWAITING_REPLY);
     741                 :            :                 }
     742                 :            :         } else {
     743         [ -  + ]:          8 :                 assert(v->state == VARLINK_CALLING);
     744                 :            : 
     745         [ -  + ]:          8 :                 if (FLAGS_SET(flags, VARLINK_REPLY_CONTINUES))
     746                 :          0 :                         goto invalid;
     747                 :            : 
     748                 :          8 :                 varlink_set_state(v, VARLINK_CALLED);
     749                 :            :         }
     750                 :            : 
     751                 :         12 :         return 1;
     752                 :            : 
     753                 :          0 : invalid:
     754                 :          0 :         varlink_set_state(v, VARLINK_PROCESSING_FAILURE);
     755                 :          0 :         varlink_dispatch_local_error(v, VARLINK_ERROR_PROTOCOL);
     756                 :          0 :         varlink_close(v);
     757                 :            : 
     758                 :          0 :         return 1;
     759                 :            : }
     760                 :            : 
     761                 :       5983 : static int varlink_dispatch_method(Varlink *v) {
     762                 :       5983 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
     763                 :       5983 :         VarlinkMethodFlags flags = 0;
     764                 :       5983 :         const char *method = NULL, *error;
     765                 :            :         JsonVariant *e;
     766                 :            :         VarlinkMethod callback;
     767                 :            :         const char *k;
     768                 :            :         int r;
     769                 :            : 
     770         [ -  + ]:       5983 :         assert(v);
     771                 :            : 
     772         [ +  + ]:       5983 :         if (v->state != VARLINK_IDLE_SERVER)
     773                 :       3297 :                 return 0;
     774         [ +  + ]:       2686 :         if (!v->current)
     775                 :       2154 :                 return 0;
     776                 :            : 
     777         [ -  + ]:        532 :         if (!json_variant_is_object(v->current))
     778                 :          0 :                 goto invalid;
     779                 :            : 
     780   [ +  -  +  +  :       2116 :         JSON_VARIANT_OBJECT_FOREACH(k, e, v->current) {
                   +  - ]
     781                 :            : 
     782         [ +  + ]:       1584 :                 if (streq(k, "method")) {
     783         [ -  + ]:        532 :                         if (method)
     784                 :          0 :                                 goto invalid;
     785         [ -  + ]:        532 :                         if (!json_variant_is_string(e))
     786                 :          0 :                                 goto invalid;
     787                 :            : 
     788                 :        532 :                         method = json_variant_string(e);
     789                 :            : 
     790         [ +  + ]:       1052 :                 } else if (streq(k, "parameters")) {
     791         [ -  + ]:        532 :                         if (parameters)
     792                 :          0 :                                 goto invalid;
     793         [ -  + ]:        532 :                         if (!json_variant_is_object(e))
     794                 :          0 :                                 goto invalid;
     795                 :            : 
     796                 :        532 :                         parameters = json_variant_ref(e);
     797                 :            : 
     798         [ +  - ]:        520 :                 } else if (streq(k, "oneway")) {
     799                 :            : 
     800         [ -  + ]:        520 :                         if ((flags & (VARLINK_METHOD_ONEWAY|VARLINK_METHOD_MORE)) != 0)
     801                 :          0 :                                 goto invalid;
     802                 :            : 
     803         [ -  + ]:        520 :                         if (!json_variant_is_boolean(e))
     804                 :          0 :                                 goto invalid;
     805                 :            : 
     806         [ +  - ]:        520 :                         if (json_variant_boolean(e))
     807                 :        520 :                                 flags |= VARLINK_METHOD_ONEWAY;
     808                 :            : 
     809         [ #  # ]:          0 :                 } else if (streq(k, "more")) {
     810                 :            : 
     811         [ #  # ]:          0 :                         if ((flags & (VARLINK_METHOD_ONEWAY|VARLINK_METHOD_MORE)) != 0)
     812                 :          0 :                                 goto invalid;
     813                 :            : 
     814         [ #  # ]:          0 :                         if (!json_variant_is_boolean(e))
     815                 :          0 :                                 goto invalid;
     816                 :            : 
     817         [ #  # ]:          0 :                         if (json_variant_boolean(e))
     818                 :          0 :                                 flags |= VARLINK_METHOD_MORE;
     819                 :            : 
     820                 :            :                 } else
     821                 :          0 :                         goto invalid;
     822                 :            :         }
     823                 :            : 
     824         [ -  + ]:        532 :         if (!method)
     825                 :          0 :                 goto invalid;
     826                 :            : 
     827                 :        532 :         r = varlink_sanitize_parameters(&parameters);
     828         [ -  + ]:        532 :         if (r < 0)
     829                 :          0 :                 goto fail;
     830                 :            : 
     831         [ +  - ]:       1064 :         varlink_set_state(v, (flags & VARLINK_METHOD_MORE)   ? VARLINK_PROCESSING_METHOD_MORE :
     832         [ +  + ]:        532 :                              (flags & VARLINK_METHOD_ONEWAY) ? VARLINK_PROCESSING_METHOD_ONEWAY :
     833                 :            :                                                                VARLINK_PROCESSING_METHOD);
     834                 :            : 
     835         [ -  + ]:        532 :         assert(v->server);
     836                 :            : 
     837         [ -  + ]:        532 :         if (STR_IN_SET(method, "org.varlink.service.GetInfo", "org.varlink.service.GetInterface")) {
     838                 :            :                 /* For now, we don't implement a single of varlink's own methods */
     839                 :          0 :                 callback = NULL;
     840                 :          0 :                 error = VARLINK_ERROR_METHOD_NOT_IMPLEMENTED;
     841         [ -  + ]:        532 :         } else if (startswith(method, "org.varlink.service.")) {
     842                 :          0 :                 callback = NULL;
     843                 :          0 :                 error = VARLINK_ERROR_METHOD_NOT_FOUND;
     844                 :            :         } else {
     845                 :        532 :                 callback = hashmap_get(v->server->methods, method);
     846                 :        532 :                 error = VARLINK_ERROR_METHOD_NOT_FOUND;
     847                 :            :         }
     848                 :            : 
     849         [ +  + ]:        532 :         if (callback) {
     850                 :         12 :                 r = callback(v, parameters, flags, v->userdata);
     851         [ -  + ]:         12 :                 if (r < 0) {
     852         [ #  # ]:          0 :                         log_debug_errno(r, "Callback for %s returned error: %m", method);
     853                 :            : 
     854                 :            :                         /* We got an error back from the callback. Propagate it to the client if the method call remains unanswered. */
     855   [ #  #  #  # ]:          0 :                         if (!FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) {
     856                 :          0 :                                 r = varlink_errorb(v, VARLINK_ERROR_SYSTEM, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("errno", JSON_BUILD_INTEGER(-r))));
     857         [ #  # ]:          0 :                                 if (r < 0)
     858                 :          0 :                                         return r;
     859                 :            :                         }
     860                 :            :                 }
     861   [ +  +  +  + ]:        520 :         } else if (!FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) {
     862         [ -  + ]:          4 :                 assert(error);
     863                 :            : 
     864                 :          4 :                 r = varlink_errorb(v, error, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method))));
     865         [ -  + ]:          4 :                 if (r < 0)
     866                 :          0 :                         return r;
     867                 :            :         }
     868                 :            : 
     869   [ +  -  -  - ]:        532 :         switch (v->state) {
     870                 :            : 
     871                 :        532 :         case VARLINK_PROCESSED_METHOD: /* Method call is fully processed */
     872                 :            :         case VARLINK_PROCESSING_METHOD_ONEWAY: /* ditto */
     873                 :        532 :                 v->current = json_variant_unref(v->current);
     874                 :        532 :                 varlink_set_state(v, VARLINK_IDLE_SERVER);
     875                 :        532 :                 break;
     876                 :            : 
     877                 :          0 :         case VARLINK_PROCESSING_METHOD: /* Method call wasn't replied to, will be replied to later */
     878                 :          0 :                 varlink_set_state(v, VARLINK_PENDING_METHOD);
     879                 :          0 :                 break;
     880                 :            : 
     881                 :          0 :         case VARLINK_PROCESSED_METHOD_MORE:  /* One reply for a "more" message was sent, more to come */
     882                 :            :         case VARLINK_PROCESSING_METHOD_MORE: /* No reply for a "more" message was sent, more to come */
     883                 :          0 :                 varlink_set_state(v, VARLINK_PENDING_METHOD_MORE);
     884                 :          0 :                 break;
     885                 :            : 
     886                 :          0 :         default:
     887                 :          0 :                 assert_not_reached("Unexpected state");
     888                 :            : 
     889                 :            :         }
     890                 :            : 
     891                 :        532 :         return r;
     892                 :            : 
     893                 :          0 : invalid:
     894                 :          0 :         r = -EINVAL;
     895                 :            : 
     896                 :          0 : fail:
     897                 :          0 :         varlink_set_state(v, VARLINK_PROCESSING_FAILURE);
     898                 :          0 :         varlink_dispatch_local_error(v, VARLINK_ERROR_PROTOCOL);
     899                 :          0 :         varlink_close(v);
     900                 :            : 
     901                 :          0 :         return r;
     902                 :            : }
     903                 :            : 
     904                 :       7355 : int varlink_process(Varlink *v) {
     905                 :            :         int r;
     906                 :            : 
     907   [ -  +  -  + ]:       7355 :         assert_return(v, -EINVAL);
     908                 :            : 
     909         [ -  + ]:       7355 :         if (v->state == VARLINK_DISCONNECTED)
     910                 :          0 :                 return -ENOTCONN;
     911                 :            : 
     912                 :       7355 :         varlink_ref(v);
     913                 :            : 
     914                 :       7355 :         r = varlink_write(v);
     915         [ +  + ]:       7355 :         if (r != 0)
     916                 :       1360 :                 goto finish;
     917                 :            : 
     918                 :       5995 :         r = varlink_dispatch_reply(v);
     919         [ +  + ]:       5995 :         if (r != 0)
     920                 :         12 :                 goto finish;
     921                 :            : 
     922                 :       5983 :         r = varlink_dispatch_method(v);
     923         [ +  + ]:       5983 :         if (r != 0)
     924                 :         12 :                 goto finish;
     925                 :            : 
     926                 :       5971 :         r = varlink_parse_message(v);
     927         [ +  + ]:       5971 :         if (r != 0)
     928                 :        544 :                 goto finish;
     929                 :            : 
     930                 :       5427 :         r = varlink_read(v);
     931         [ +  + ]:       5427 :         if (r != 0)
     932                 :        833 :                 goto finish;
     933                 :            : 
     934                 :       4594 :         r = varlink_test_disconnect(v);
     935         [ +  + ]:       4594 :         if (r != 0)
     936                 :       1097 :                 goto finish;
     937                 :            : 
     938                 :       3497 :         r = varlink_dispatch_disconnect(v);
     939         [ +  + ]:       3497 :         if (r != 0)
     940                 :       1101 :                 goto finish;
     941                 :            : 
     942                 :       2396 :         r = varlink_test_timeout(v);
     943         [ -  + ]:       2396 :         if (r != 0)
     944                 :          0 :                 goto finish;
     945                 :            : 
     946                 :       2396 :         r = varlink_dispatch_timeout(v);
     947         [ +  - ]:       2396 :         if (r != 0)
     948                 :          0 :                 goto finish;
     949                 :            : 
     950                 :       2396 : finish:
     951   [ +  +  +  + ]:       7355 :         if (r >= 0 && v->defer_event_source) {
     952                 :            :                 int q;
     953                 :            : 
     954                 :            :                 /* If we did some processing, make sure we are called again soon */
     955                 :       6210 :                 q = sd_event_source_set_enabled(v->defer_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF);
     956         [ -  + ]:       6210 :                 if (q < 0)
     957                 :          0 :                         r = q;
     958                 :            :         }
     959                 :            : 
     960         [ +  + ]:       7355 :         if (r < 0) {
     961   [ +  -  +  - ]:          4 :                 if (VARLINK_STATE_IS_ALIVE(v->state))
     962                 :            :                         /* Initiate disconnection */
     963                 :          4 :                         varlink_set_state(v, VARLINK_PENDING_DISCONNECT);
     964                 :            :                 else
     965                 :            :                         /* We failed while disconnecting, in that case close right away */
     966                 :          0 :                         varlink_close(v);
     967                 :            :         }
     968                 :            : 
     969                 :       7355 :         varlink_unref(v);
     970                 :       7355 :         return r;
     971                 :            : }
     972                 :            : 
     973                 :       1637 : static void handle_revents(Varlink *v, int revents) {
     974         [ -  + ]:       1637 :         assert(v);
     975                 :            : 
     976         [ +  + ]:       1637 :         if (v->connecting) {
     977                 :            :                 /* If we have seen POLLOUT or POLLHUP on a socket we are asynchronously waiting a connect()
     978                 :            :                  * to complete on, we know we are ready. We don't read the connection error here though,
     979                 :            :                  * we'll get the error on the next read() or write(). */
     980         [ -  + ]:        820 :                 if ((revents & (POLLOUT|POLLHUP)) == 0)
     981                 :          0 :                         return;
     982                 :            : 
     983         [ +  - ]:        820 :                 varlink_log(v, "Anynchronous connection completed.");
     984                 :        820 :                 v->connecting = false;
     985                 :            :         } else {
     986                 :            :                 /* Note that we don't care much about POLLIN/POLLOUT here, we'll just try reading and writing
     987                 :            :                  * what we can. However, we do care about POLLHUP to detect connection termination even if we
     988                 :            :                  * momentarily don't want to read nor write anything. */
     989                 :            : 
     990         [ +  + ]:        817 :                 if (!FLAGS_SET(revents, POLLHUP))
     991                 :        532 :                         return;
     992                 :            : 
     993         [ +  - ]:        285 :                 varlink_log(v, "Got POLLHUP from socket.");
     994                 :        285 :                 v->got_pollhup = true;
     995                 :            :         }
     996                 :            : }
     997                 :            : 
     998                 :          8 : int varlink_wait(Varlink *v, usec_t timeout) {
     999                 :            :         struct timespec ts;
    1000                 :            :         struct pollfd pfd;
    1001                 :            :         int r, fd, events;
    1002                 :            :         usec_t t;
    1003                 :            : 
    1004   [ -  +  -  + ]:          8 :         assert_return(v, -EINVAL);
    1005                 :            : 
    1006         [ -  + ]:          8 :         if (v->state == VARLINK_DISCONNECTED)
    1007                 :          0 :                 return -ENOTCONN;
    1008                 :            : 
    1009                 :          8 :         r = varlink_get_timeout(v, &t);
    1010         [ -  + ]:          8 :         if (r < 0)
    1011                 :          0 :                 return r;
    1012         [ +  - ]:          8 :         if (t != USEC_INFINITY) {
    1013                 :            :                 usec_t n;
    1014                 :            : 
    1015                 :          8 :                 n = now(CLOCK_MONOTONIC);
    1016         [ -  + ]:          8 :                 if (t < n)
    1017                 :          0 :                         t = 0;
    1018                 :            :                 else
    1019                 :          8 :                         t = usec_sub_unsigned(t, n);
    1020                 :            :         }
    1021                 :            : 
    1022         [ -  + ]:          8 :         if (timeout != USEC_INFINITY &&
    1023   [ #  #  #  # ]:          0 :             (t == USEC_INFINITY || timeout < t))
    1024                 :          0 :                 t = timeout;
    1025                 :            : 
    1026                 :          8 :         fd = varlink_get_fd(v);
    1027         [ -  + ]:          8 :         if (fd < 0)
    1028                 :          0 :                 return fd;
    1029                 :            : 
    1030                 :          8 :         events = varlink_get_events(v);
    1031         [ -  + ]:          8 :         if (events < 0)
    1032                 :          0 :                 return events;
    1033                 :            : 
    1034                 :          8 :         pfd = (struct pollfd) {
    1035                 :            :                 .fd = fd,
    1036                 :            :                 .events = events,
    1037                 :            :         };
    1038                 :            : 
    1039                 :          8 :         r = ppoll(&pfd, 1,
    1040         [ +  - ]:          8 :                   t == USEC_INFINITY ? NULL : timespec_store(&ts, t),
    1041                 :            :                   NULL);
    1042         [ -  + ]:          8 :         if (r < 0)
    1043                 :          0 :                 return -errno;
    1044                 :            : 
    1045                 :          8 :         handle_revents(v, pfd.revents);
    1046                 :            : 
    1047                 :          8 :         return r > 0 ? 1 : 0;
    1048                 :            : }
    1049                 :            : 
    1050                 :          8 : int varlink_get_fd(Varlink *v) {
    1051                 :            : 
    1052   [ -  +  -  + ]:          8 :         assert_return(v, -EINVAL);
    1053                 :            : 
    1054         [ -  + ]:          8 :         if (v->state == VARLINK_DISCONNECTED)
    1055                 :          0 :                 return -ENOTCONN;
    1056         [ -  + ]:          8 :         if (v->fd < 0)
    1057                 :          0 :                 return -EBADF;
    1058                 :            : 
    1059                 :          8 :         return v->fd;
    1060                 :            : }
    1061                 :            : 
    1062                 :    1435599 : int varlink_get_events(Varlink *v) {
    1063                 :    1435599 :         int ret = 0;
    1064                 :            : 
    1065   [ -  +  -  + ]:    1435599 :         assert_return(v, -EINVAL);
    1066                 :            : 
    1067         [ -  + ]:    1435599 :         if (v->state == VARLINK_DISCONNECTED)
    1068                 :          0 :                 return -ENOTCONN;
    1069                 :            : 
    1070         [ +  + ]:    1435599 :         if (v->connecting) /* When processing an asynchronous connect(), we only wait for EPOLLOUT, which
    1071                 :            :                             * tells us that the connection is now complete. Before that we should neither
    1072                 :            :                             * write() or read() from the fd. */
    1073                 :     547760 :                 return EPOLLOUT;
    1074                 :            : 
    1075         [ +  + ]:     887839 :         if (!v->read_disconnected &&
    1076   [ +  +  +  + ]:     887277 :             IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) &&
    1077         [ +  + ]:     325910 :             !v->current &&
    1078         [ +  + ]:     325374 :             v->input_buffer_unscanned <= 0)
    1079                 :     324838 :                 ret |= EPOLLIN;
    1080                 :            : 
    1081         [ +  + ]:     887839 :         if (!v->write_disconnected &&
    1082         [ +  + ]:     886199 :             v->output_buffer_size > 0)
    1083                 :      66580 :                 ret |= EPOLLOUT;
    1084                 :            : 
    1085                 :     887839 :         return ret;
    1086                 :            : }
    1087                 :            : 
    1088                 :    1435599 : int varlink_get_timeout(Varlink *v, usec_t *ret) {
    1089   [ -  +  -  + ]:    1435599 :         assert_return(v, -EINVAL);
    1090                 :            : 
    1091         [ -  + ]:    1435599 :         if (v->state == VARLINK_DISCONNECTED)
    1092                 :          0 :                 return -ENOTCONN;
    1093                 :            : 
    1094   [ +  +  +  + ]:    1435599 :         if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING) &&
    1095         [ +  - ]:       4364 :             v->timeout != USEC_INFINITY) {
    1096         [ +  - ]:       4364 :                 if (ret)
    1097                 :       4364 :                         *ret = usec_add(v->timestamp, v->timeout);
    1098                 :       4364 :                 return 1;
    1099                 :            :         } else {
    1100         [ +  - ]:    1431235 :                 if (ret)
    1101                 :    1431235 :                         *ret = USEC_INFINITY;
    1102                 :    1431235 :                 return 0;
    1103                 :            :         }
    1104                 :            : }
    1105                 :            : 
    1106                 :        775 : int varlink_flush(Varlink *v) {
    1107                 :        775 :         int ret = 0, r;
    1108                 :            : 
    1109   [ -  +  -  + ]:        775 :         assert_return(v, -EINVAL);
    1110                 :            : 
    1111         [ +  + ]:        775 :         if (v->state == VARLINK_DISCONNECTED)
    1112                 :          8 :                 return -ENOTCONN;
    1113                 :            : 
    1114                 :          4 :         for (;;) {
    1115                 :            :                 struct pollfd pfd;
    1116                 :            : 
    1117         [ +  + ]:        771 :                 if (v->output_buffer_size == 0)
    1118                 :        767 :                         break;
    1119         [ -  + ]:          4 :                 if (v->write_disconnected)
    1120                 :          0 :                         return -ECONNRESET;
    1121                 :            : 
    1122                 :          4 :                 r = varlink_write(v);
    1123         [ -  + ]:          4 :                 if (r < 0)
    1124                 :          0 :                         return r;
    1125         [ +  - ]:          4 :                 if (r > 0) {
    1126                 :          4 :                         ret = 1;
    1127                 :          4 :                         continue;
    1128                 :            :                 }
    1129                 :            : 
    1130                 :          0 :                 pfd = (struct pollfd) {
    1131                 :          0 :                         .fd = v->fd,
    1132                 :            :                         .events = POLLOUT,
    1133                 :            :                 };
    1134                 :            : 
    1135         [ #  # ]:          0 :                 if (poll(&pfd, 1, -1) < 0)
    1136                 :          0 :                         return -errno;
    1137                 :            : 
    1138                 :          0 :                 handle_revents(v, pfd.revents);
    1139                 :            :         }
    1140                 :            : 
    1141                 :        767 :         return ret;
    1142                 :            : }
    1143                 :            : 
    1144                 :       1868 : static void varlink_detach_server(Varlink *v) {
    1145         [ -  + ]:       1868 :         assert(v);
    1146                 :            : 
    1147         [ +  + ]:       1868 :         if (!v->server)
    1148                 :       1344 :                 return;
    1149                 :            : 
    1150   [ +  -  +  - ]:        524 :         if (v->server->by_uid &&
    1151         [ +  - ]:        524 :             v->ucred_acquired &&
    1152                 :        524 :             uid_is_valid(v->ucred.uid)) {
    1153                 :            :                 unsigned c;
    1154                 :            : 
    1155                 :        524 :                 c = PTR_TO_UINT(hashmap_get(v->server->by_uid, UID_TO_PTR(v->ucred.uid)));
    1156         [ -  + ]:        524 :                 assert(c > 0);
    1157                 :            : 
    1158         [ +  + ]:        524 :                 if (c == 1)
    1159                 :          4 :                         (void) hashmap_remove(v->server->by_uid, UID_TO_PTR(v->ucred.uid));
    1160                 :            :                 else
    1161                 :        520 :                         (void) hashmap_replace(v->server->by_uid, UID_TO_PTR(v->ucred.uid), UINT_TO_PTR(c - 1));
    1162                 :            :         }
    1163                 :            : 
    1164         [ -  + ]:        524 :         assert(v->server->n_connections > 0);
    1165                 :        524 :         v->server->n_connections--;
    1166                 :            : 
    1167                 :            :         /* If this is a connection associated to a server, then let's disconnect the server and the
    1168                 :            :          * connection from each other. This drops the dangling reference that connect_callback() set up. */
    1169                 :        524 :         v->server = varlink_server_unref(v->server);
    1170                 :        524 :         varlink_unref(v);
    1171                 :            : }
    1172                 :            : 
    1173                 :       1876 : int varlink_close(Varlink *v) {
    1174                 :            : 
    1175   [ -  +  -  + ]:       1876 :         assert_return(v, -EINVAL);
    1176                 :            : 
    1177         [ +  + ]:       1876 :         if (v->state == VARLINK_DISCONNECTED)
    1178                 :          8 :                 return 0;
    1179                 :            : 
    1180                 :       1868 :         varlink_set_state(v, VARLINK_DISCONNECTED);
    1181                 :            : 
    1182                 :            :         /* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref
    1183                 :            :          * which would destroy us before we can call varlink_clear() */
    1184                 :       1868 :         varlink_ref(v);
    1185                 :       1868 :         varlink_detach_server(v);
    1186                 :       1868 :         varlink_clear(v);
    1187                 :       1868 :         varlink_unref(v);
    1188                 :            : 
    1189                 :       1868 :         return 1;
    1190                 :            : }
    1191                 :            : 
    1192                 :         12 : Varlink* varlink_flush_close_unref(Varlink *v) {
    1193                 :            : 
    1194         [ -  + ]:         12 :         if (!v)
    1195                 :          0 :                 return NULL;
    1196                 :            : 
    1197                 :         12 :         (void) varlink_flush(v);
    1198                 :         12 :         (void) varlink_close(v);
    1199                 :            : 
    1200                 :         12 :         return varlink_unref(v);
    1201                 :            : }
    1202                 :            : 
    1203                 :       1364 : static int varlink_enqueue_json(Varlink *v, JsonVariant *m) {
    1204                 :       1364 :         _cleanup_free_ char *text = NULL;
    1205                 :            :         int r;
    1206                 :            : 
    1207         [ -  + ]:       1364 :         assert(v);
    1208         [ -  + ]:       1364 :         assert(m);
    1209                 :            : 
    1210                 :       1364 :         r = json_variant_format(m, 0, &text);
    1211         [ -  + ]:       1364 :         if (r < 0)
    1212                 :          0 :                 return r;
    1213         [ -  + ]:       1364 :         assert(text[r] == '\0');
    1214                 :            : 
    1215         [ -  + ]:       1364 :         if (v->output_buffer_size + r + 1 > VARLINK_BUFFER_MAX)
    1216                 :          0 :                 return -ENOBUFS;
    1217                 :            : 
    1218         [ +  - ]:       1364 :         varlink_log(v, "Sending message: %s", text);
    1219                 :            : 
    1220         [ +  - ]:       1364 :         if (v->output_buffer_size == 0) {
    1221                 :            : 
    1222                 :       1364 :                 free_and_replace(v->output_buffer, text);
    1223                 :            : 
    1224                 :       1364 :                 v->output_buffer_size = v->output_buffer_allocated = r + 1;
    1225                 :       1364 :                 v->output_buffer_index = 0;
    1226                 :            : 
    1227         [ #  # ]:          0 :         } else if (v->output_buffer_index == 0) {
    1228                 :            : 
    1229         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(v->output_buffer, v->output_buffer_allocated, v->output_buffer_size + r + 1))
    1230                 :          0 :                         return -ENOMEM;
    1231                 :            : 
    1232                 :          0 :                 memcpy(v->output_buffer + v->output_buffer_size, text, r + 1);
    1233                 :          0 :                 v->output_buffer_size += r + 1;
    1234                 :            : 
    1235                 :            :         } else {
    1236                 :            :                 char *n;
    1237                 :          0 :                 const size_t new_size = v->output_buffer_size + r + 1;
    1238                 :            : 
    1239                 :          0 :                 n = new(char, new_size);
    1240         [ #  # ]:          0 :                 if (!n)
    1241                 :          0 :                         return -ENOMEM;
    1242                 :            : 
    1243                 :          0 :                 memcpy(mempcpy(n, v->output_buffer + v->output_buffer_index, v->output_buffer_size), text, r + 1);
    1244                 :            : 
    1245                 :          0 :                 free_and_replace(v->output_buffer, n);
    1246                 :          0 :                 v->output_buffer_allocated = v->output_buffer_size = new_size;
    1247                 :          0 :                 v->output_buffer_index = 0;
    1248                 :            :         }
    1249                 :            : 
    1250                 :       1364 :         return 0;
    1251                 :            : }
    1252                 :            : 
    1253                 :       1336 : int varlink_send(Varlink *v, const char *method, JsonVariant *parameters) {
    1254                 :       1336 :         _cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
    1255                 :            :         int r;
    1256                 :            : 
    1257   [ -  +  -  + ]:       1336 :         assert_return(v, -EINVAL);
    1258   [ -  +  -  + ]:       1336 :         assert_return(method, -EINVAL);
    1259                 :            : 
    1260         [ -  + ]:       1336 :         if (v->state == VARLINK_DISCONNECTED)
    1261                 :          0 :                 return -ENOTCONN;
    1262   [ +  -  -  + ]:       1336 :         if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
    1263                 :          0 :                 return -EBUSY;
    1264                 :            : 
    1265                 :       1336 :         r = varlink_sanitize_parameters(&parameters);
    1266         [ -  + ]:       1336 :         if (r < 0)
    1267                 :          0 :                 return r;
    1268                 :            : 
    1269                 :       1336 :         r = json_build(&m, JSON_BUILD_OBJECT(
    1270                 :            :                                        JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)),
    1271                 :            :                                        JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)),
    1272                 :            :                                        JSON_BUILD_PAIR("oneway", JSON_BUILD_BOOLEAN(true))));
    1273         [ -  + ]:       1336 :         if (r < 0)
    1274                 :          0 :                 return r;
    1275                 :            : 
    1276                 :       1336 :         r = varlink_enqueue_json(v, m);
    1277         [ -  + ]:       1336 :         if (r < 0)
    1278                 :          0 :                 return r;
    1279                 :            : 
    1280                 :            :         /* No state change here, this is one-way only after all */
    1281                 :       1336 :         v->timestamp = now(CLOCK_MONOTONIC);
    1282                 :       1336 :         return 0;
    1283                 :            : }
    1284                 :            : 
    1285                 :       1332 : int varlink_sendb(Varlink *v, const char *method, ...) {
    1286                 :       1332 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
    1287                 :            :         va_list ap;
    1288                 :            :         int r;
    1289                 :            : 
    1290   [ -  +  -  + ]:       1332 :         assert_return(v, -EINVAL);
    1291                 :            : 
    1292                 :       1332 :         va_start(ap, method);
    1293                 :       1332 :         r = json_buildv(&parameters, ap);
    1294                 :       1332 :         va_end(ap);
    1295                 :            : 
    1296         [ -  + ]:       1332 :         if (r < 0)
    1297                 :          0 :                 return r;
    1298                 :            : 
    1299                 :       1332 :         return varlink_send(v, method, parameters);
    1300                 :            : }
    1301                 :            : 
    1302                 :          8 : int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters) {
    1303                 :          8 :         _cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
    1304                 :            :         int r;
    1305                 :            : 
    1306   [ -  +  -  + ]:          8 :         assert_return(v, -EINVAL);
    1307   [ -  +  -  + ]:          8 :         assert_return(method, -EINVAL);
    1308                 :            : 
    1309         [ -  + ]:          8 :         if (v->state == VARLINK_DISCONNECTED)
    1310                 :          0 :                 return -ENOTCONN;
    1311   [ +  -  -  + ]:          8 :         if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY))
    1312                 :          0 :                 return -EBUSY;
    1313                 :            : 
    1314                 :          8 :         r = varlink_sanitize_parameters(&parameters);
    1315         [ -  + ]:          8 :         if (r < 0)
    1316                 :          0 :                 return r;
    1317                 :            : 
    1318                 :          8 :         r = json_build(&m, JSON_BUILD_OBJECT(
    1319                 :            :                                        JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)),
    1320                 :            :                                        JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters))));
    1321         [ -  + ]:          8 :         if (r < 0)
    1322                 :          0 :                 return r;
    1323                 :            : 
    1324                 :          8 :         r = varlink_enqueue_json(v, m);
    1325         [ -  + ]:          8 :         if (r < 0)
    1326                 :          0 :                 return r;
    1327                 :            : 
    1328                 :          8 :         varlink_set_state(v, VARLINK_AWAITING_REPLY);
    1329                 :          8 :         v->n_pending++;
    1330                 :          8 :         v->timestamp = now(CLOCK_MONOTONIC);
    1331                 :            : 
    1332                 :          8 :         return 0;
    1333                 :            : }
    1334                 :            : 
    1335                 :          4 : int varlink_invokeb(Varlink *v, const char *method, ...) {
    1336                 :          4 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
    1337                 :            :         va_list ap;
    1338                 :            :         int r;
    1339                 :            : 
    1340   [ -  +  -  + ]:          4 :         assert_return(v, -EINVAL);
    1341                 :            : 
    1342                 :          4 :         va_start(ap, method);
    1343                 :          4 :         r = json_buildv(&parameters, ap);
    1344                 :          4 :         va_end(ap);
    1345                 :            : 
    1346         [ -  + ]:          4 :         if (r < 0)
    1347                 :          0 :                 return r;
    1348                 :            : 
    1349                 :          4 :         return varlink_invoke(v, method, parameters);
    1350                 :            : }
    1351                 :            : 
    1352                 :          8 : int varlink_call(
    1353                 :            :                 Varlink *v,
    1354                 :            :                 const char *method,
    1355                 :            :                 JsonVariant *parameters,
    1356                 :            :                 JsonVariant **ret_parameters,
    1357                 :            :                 const char **ret_error_id,
    1358                 :            :                 VarlinkReplyFlags *ret_flags) {
    1359                 :            : 
    1360                 :          8 :         _cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
    1361                 :            :         int r;
    1362                 :            : 
    1363   [ -  +  -  + ]:          8 :         assert_return(v, -EINVAL);
    1364   [ -  +  -  + ]:          8 :         assert_return(method, -EINVAL);
    1365                 :            : 
    1366         [ -  + ]:          8 :         if (v->state == VARLINK_DISCONNECTED)
    1367                 :          0 :                 return -ENOTCONN;
    1368   [ +  -  -  + ]:          8 :         if (!IN_SET(v->state, VARLINK_IDLE_CLIENT))
    1369                 :          0 :                 return -EBUSY;
    1370                 :            : 
    1371         [ -  + ]:          8 :         assert(v->n_pending == 0); /* n_pending can't be > 0 if we are in VARLINK_IDLE_CLIENT state */
    1372                 :            : 
    1373                 :          8 :         r = varlink_sanitize_parameters(&parameters);
    1374         [ -  + ]:          8 :         if (r < 0)
    1375                 :          0 :                 return r;
    1376                 :            : 
    1377                 :          8 :         r = json_build(&m, JSON_BUILD_OBJECT(
    1378                 :            :                                        JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)),
    1379                 :            :                                        JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters))));
    1380         [ -  + ]:          8 :         if (r < 0)
    1381                 :          0 :                 return r;
    1382                 :            : 
    1383                 :          8 :         r = varlink_enqueue_json(v, m);
    1384         [ -  + ]:          8 :         if (r < 0)
    1385                 :          0 :                 return r;
    1386                 :            : 
    1387                 :          8 :         varlink_set_state(v, VARLINK_CALLING);
    1388                 :          8 :         v->n_pending++;
    1389                 :          8 :         v->timestamp = now(CLOCK_MONOTONIC);
    1390                 :            : 
    1391         [ +  + ]:         48 :         while (v->state == VARLINK_CALLING) {
    1392                 :            : 
    1393                 :         40 :                 r = varlink_process(v);
    1394         [ -  + ]:         40 :                 if (r < 0)
    1395                 :          0 :                         return r;
    1396         [ +  + ]:         40 :                 if (r > 0)
    1397                 :         32 :                         continue;
    1398                 :            : 
    1399                 :          8 :                 r = varlink_wait(v, USEC_INFINITY);
    1400         [ -  + ]:          8 :                 if (r < 0)
    1401                 :          0 :                         return r;
    1402                 :            :         }
    1403                 :            : 
    1404   [ +  -  -  - ]:          8 :         switch (v->state) {
    1405                 :            : 
    1406                 :          8 :         case VARLINK_CALLED:
    1407         [ -  + ]:          8 :                 assert(v->current);
    1408                 :            : 
    1409                 :          8 :                 json_variant_unref(v->reply);
    1410                 :          8 :                 v->reply = TAKE_PTR(v->current);
    1411                 :            : 
    1412                 :          8 :                 varlink_set_state(v, VARLINK_IDLE_CLIENT);
    1413         [ -  + ]:          8 :                 assert(v->n_pending == 1);
    1414                 :          8 :                 v->n_pending--;
    1415                 :            : 
    1416         [ +  - ]:          8 :                 if (ret_parameters)
    1417                 :          8 :                         *ret_parameters = json_variant_by_key(v->reply, "parameters");
    1418         [ +  - ]:          8 :                 if (ret_error_id)
    1419                 :          8 :                         *ret_error_id = json_variant_string(json_variant_by_key(v->reply, "error"));
    1420         [ -  + ]:          8 :                 if (ret_flags)
    1421                 :          0 :                         *ret_flags = 0;
    1422                 :            : 
    1423                 :          8 :                 return 1;
    1424                 :            : 
    1425                 :          0 :         case VARLINK_PENDING_DISCONNECT:
    1426                 :            :         case VARLINK_DISCONNECTED:
    1427                 :          0 :                 return -ECONNRESET;
    1428                 :            : 
    1429                 :          0 :         case VARLINK_PENDING_TIMEOUT:
    1430                 :          0 :                 return -ETIME;
    1431                 :            : 
    1432                 :          0 :         default:
    1433                 :          0 :                 assert_not_reached("Unexpected state after method call.");
    1434                 :            :         }
    1435                 :            : }
    1436                 :            : 
    1437                 :          4 : int varlink_callb(
    1438                 :            :                 Varlink *v,
    1439                 :            :                 const char *method,
    1440                 :            :                 JsonVariant **ret_parameters,
    1441                 :            :                 const char **ret_error_id,
    1442                 :            :                 VarlinkReplyFlags *ret_flags, ...) {
    1443                 :            : 
    1444                 :          4 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
    1445                 :            :         va_list ap;
    1446                 :            :         int r;
    1447                 :            : 
    1448   [ -  +  -  + ]:          4 :         assert_return(v, -EINVAL);
    1449                 :            : 
    1450                 :          4 :         va_start(ap, ret_flags);
    1451                 :          4 :         r = json_buildv(&parameters, ap);
    1452                 :          4 :         va_end(ap);
    1453                 :            : 
    1454         [ -  + ]:          4 :         if (r < 0)
    1455                 :          0 :                 return r;
    1456                 :            : 
    1457                 :          4 :         return varlink_call(v, method, parameters, ret_parameters, ret_error_id, ret_flags);
    1458                 :            : }
    1459                 :            : 
    1460                 :          8 : int varlink_reply(Varlink *v, JsonVariant *parameters) {
    1461                 :          8 :         _cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
    1462                 :            :         int r;
    1463                 :            : 
    1464   [ -  +  -  + ]:          8 :         assert_return(v, -EINVAL);
    1465                 :            : 
    1466         [ -  + ]:          8 :         if (v->state == VARLINK_DISCONNECTED)
    1467                 :          0 :                 return -ENOTCONN;
    1468   [ +  -  -  + ]:          8 :         if (!IN_SET(v->state,
    1469                 :            :                     VARLINK_PROCESSING_METHOD, VARLINK_PROCESSING_METHOD_MORE,
    1470                 :            :                     VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE))
    1471                 :          0 :                 return -EBUSY;
    1472                 :            : 
    1473                 :          8 :         r = varlink_sanitize_parameters(&parameters);
    1474         [ -  + ]:          8 :         if (r < 0)
    1475                 :          0 :                 return r;
    1476                 :            : 
    1477                 :          8 :         r = json_build(&m, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters))));
    1478         [ -  + ]:          8 :         if (r < 0)
    1479                 :          0 :                 return r;
    1480                 :            : 
    1481                 :          8 :         r = varlink_enqueue_json(v, m);
    1482         [ -  + ]:          8 :         if (r < 0)
    1483                 :          0 :                 return r;
    1484                 :            : 
    1485   [ -  +  -  + ]:          8 :         if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) {
    1486                 :            :                 /* We just replied to a method call that was let hanging for a while (i.e. we were outside of
    1487                 :            :                  * the varlink_dispatch_method() stack frame), which means with this reply we are ready to
    1488                 :            :                  * process further messages. */
    1489                 :          0 :                 v->current = json_variant_unref(v->current);
    1490                 :          0 :                 varlink_set_state(v, VARLINK_IDLE_SERVER);
    1491                 :            :         } else
    1492                 :            :                 /* We replied to a method call from within the varlink_dispatch_method() stack frame), which
    1493                 :            :                  * means we should it handle the rest of the state engine. */
    1494                 :          8 :                 varlink_set_state(v, VARLINK_PROCESSED_METHOD);
    1495                 :            : 
    1496                 :          8 :         return 1;
    1497                 :            : }
    1498                 :            : 
    1499                 :          0 : int varlink_replyb(Varlink *v, ...) {
    1500                 :          0 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
    1501                 :            :         va_list ap;
    1502                 :            :         int r;
    1503                 :            : 
    1504   [ #  #  #  # ]:          0 :         assert_return(v, -EINVAL);
    1505                 :            : 
    1506                 :          0 :         va_start(ap, v);
    1507                 :          0 :         r = json_buildv(&parameters, ap);
    1508                 :          0 :         va_end(ap);
    1509                 :            : 
    1510         [ #  # ]:          0 :         if (r < 0)
    1511                 :          0 :                 return r;
    1512                 :            : 
    1513                 :          0 :         return varlink_reply(v, parameters);
    1514                 :            : }
    1515                 :            : 
    1516                 :          4 : int varlink_error(Varlink *v, const char *error_id, JsonVariant *parameters) {
    1517                 :          4 :         _cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
    1518                 :            :         int r;
    1519                 :            : 
    1520   [ -  +  -  + ]:          4 :         assert_return(v, -EINVAL);
    1521   [ -  +  -  + ]:          4 :         assert_return(error_id, -EINVAL);
    1522                 :            : 
    1523         [ -  + ]:          4 :         if (v->state == VARLINK_DISCONNECTED)
    1524                 :          0 :                 return -ENOTCONN;
    1525   [ +  -  -  + ]:          4 :         if (!IN_SET(v->state,
    1526                 :            :                     VARLINK_PROCESSING_METHOD, VARLINK_PROCESSING_METHOD_MORE,
    1527                 :            :                     VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE))
    1528                 :          0 :                 return -EBUSY;
    1529                 :            : 
    1530                 :          4 :         r = varlink_sanitize_parameters(&parameters);
    1531         [ -  + ]:          4 :         if (r < 0)
    1532                 :          0 :                 return r;
    1533                 :            : 
    1534                 :          4 :         r = json_build(&m, JSON_BUILD_OBJECT(
    1535                 :            :                                        JSON_BUILD_PAIR("error", JSON_BUILD_STRING(error_id)),
    1536                 :            :                                        JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters))));
    1537         [ -  + ]:          4 :         if (r < 0)
    1538                 :          0 :                 return r;
    1539                 :            : 
    1540                 :          4 :         r = varlink_enqueue_json(v, m);
    1541         [ -  + ]:          4 :         if (r < 0)
    1542                 :          0 :                 return r;
    1543                 :            : 
    1544   [ -  +  -  + ]:          4 :         if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) {
    1545                 :          0 :                 v->current = json_variant_unref(v->current);
    1546                 :          0 :                 varlink_set_state(v, VARLINK_IDLE_SERVER);
    1547                 :            :         } else
    1548                 :          4 :                 varlink_set_state(v, VARLINK_PROCESSED_METHOD);
    1549                 :            : 
    1550                 :          4 :         return 1;
    1551                 :            : }
    1552                 :            : 
    1553                 :          4 : int varlink_errorb(Varlink *v, const char *error_id, ...) {
    1554                 :          4 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
    1555                 :            :         va_list ap;
    1556                 :            :         int r;
    1557                 :            : 
    1558   [ -  +  -  + ]:          4 :         assert_return(v, -EINVAL);
    1559   [ -  +  -  + ]:          4 :         assert_return(error_id, -EINVAL);
    1560                 :            : 
    1561                 :          4 :         va_start(ap, error_id);
    1562                 :          4 :         r = json_buildv(&parameters, ap);
    1563                 :          4 :         va_end(ap);
    1564                 :            : 
    1565         [ -  + ]:          4 :         if (r < 0)
    1566                 :          0 :                 return r;
    1567                 :            : 
    1568                 :          4 :         return varlink_error(v, error_id, parameters);
    1569                 :            : }
    1570                 :            : 
    1571                 :          0 : int varlink_error_invalid_parameter(Varlink *v, JsonVariant *parameters) {
    1572                 :            : 
    1573   [ #  #  #  # ]:          0 :         assert_return(v, -EINVAL);
    1574   [ #  #  #  # ]:          0 :         assert_return(parameters, -EINVAL);
    1575                 :            : 
    1576                 :            :         /* We expect to be called in one of two ways: the 'parameters' argument is a string variant in which
    1577                 :            :          * case it is the parameter key name that is invalid. Or the 'parameters' argument is an object
    1578                 :            :          * variant in which case we'll pull out the first key. The latter mode is useful in functions that
    1579                 :            :          * don't expect any arguments. */
    1580                 :            : 
    1581         [ #  # ]:          0 :         if (json_variant_is_string(parameters))
    1582                 :          0 :                 return varlink_error(v, VARLINK_ERROR_INVALID_PARAMETER, parameters);
    1583                 :            : 
    1584   [ #  #  #  # ]:          0 :         if (json_variant_is_object(parameters) &&
    1585                 :          0 :             json_variant_elements(parameters) > 0)
    1586                 :          0 :                 return varlink_error(v, VARLINK_ERROR_INVALID_PARAMETER,
    1587                 :            :                                      json_variant_by_index(parameters, 0));
    1588                 :            : 
    1589                 :          0 :         return -EINVAL;
    1590                 :            : }
    1591                 :            : 
    1592                 :          0 : int varlink_notify(Varlink *v, JsonVariant *parameters) {
    1593                 :          0 :         _cleanup_(json_variant_unrefp) JsonVariant *m = NULL;
    1594                 :            :         int r;
    1595                 :            : 
    1596   [ #  #  #  # ]:          0 :         assert_return(v, -EINVAL);
    1597                 :            : 
    1598         [ #  # ]:          0 :         if (v->state == VARLINK_DISCONNECTED)
    1599                 :          0 :                 return -ENOTCONN;
    1600   [ #  #  #  # ]:          0 :         if (!IN_SET(v->state, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PENDING_METHOD_MORE))
    1601                 :          0 :                 return -EBUSY;
    1602                 :            : 
    1603                 :          0 :         r = varlink_sanitize_parameters(&parameters);
    1604         [ #  # ]:          0 :         if (r < 0)
    1605                 :          0 :                 return r;
    1606                 :            : 
    1607                 :          0 :         r = json_build(&m, JSON_BUILD_OBJECT(
    1608                 :            :                                        JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)),
    1609                 :            :                                        JSON_BUILD_PAIR("continues", JSON_BUILD_BOOLEAN(true))));
    1610         [ #  # ]:          0 :         if (r < 0)
    1611                 :          0 :                 return r;
    1612                 :            : 
    1613                 :          0 :         r = varlink_enqueue_json(v, m);
    1614         [ #  # ]:          0 :         if (r < 0)
    1615                 :          0 :                 return r;
    1616                 :            : 
    1617                 :            :         /* No state change, as more is coming */
    1618                 :          0 :         return 1;
    1619                 :            : }
    1620                 :            : 
    1621                 :          0 : int varlink_notifyb(Varlink *v, ...) {
    1622                 :          0 :         _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL;
    1623                 :            :         va_list ap;
    1624                 :            :         int r;
    1625                 :            : 
    1626   [ #  #  #  # ]:          0 :         assert_return(v, -EINVAL);
    1627                 :            : 
    1628                 :          0 :         va_start(ap, v);
    1629                 :          0 :         r = json_buildv(&parameters, ap);
    1630                 :          0 :         va_end(ap);
    1631                 :            : 
    1632         [ #  # ]:          0 :         if (r < 0)
    1633                 :          0 :                 return r;
    1634                 :            : 
    1635                 :          0 :         return varlink_notify(v, parameters);
    1636                 :            : }
    1637                 :            : 
    1638                 :          8 : int varlink_bind_reply(Varlink *v, VarlinkReply callback) {
    1639   [ -  +  -  + ]:          8 :         assert_return(v, -EINVAL);
    1640                 :            : 
    1641   [ +  -  -  +  :          8 :         if (callback && v->reply_callback && callback != v->reply_callback)
                   #  # ]
    1642                 :          0 :                 return -EBUSY;
    1643                 :            : 
    1644                 :          8 :         v->reply_callback = callback;
    1645                 :            : 
    1646                 :          8 :         return 0;
    1647                 :            : }
    1648                 :            : 
    1649                 :          0 : void* varlink_set_userdata(Varlink *v, void *userdata) {
    1650                 :            :         void *old;
    1651                 :            : 
    1652   [ #  #  #  # ]:          0 :         assert_return(v, NULL);
    1653                 :            : 
    1654                 :          0 :         old = v->userdata;
    1655                 :          0 :         v->userdata = userdata;
    1656                 :            : 
    1657                 :          0 :         return old;
    1658                 :            : }
    1659                 :            : 
    1660                 :          0 : void* varlink_get_userdata(Varlink *v) {
    1661   [ #  #  #  # ]:          0 :         assert_return(v, NULL);
    1662                 :            : 
    1663                 :          0 :         return v->userdata;
    1664                 :            : }
    1665                 :            : 
    1666                 :        524 : static int varlink_acquire_ucred(Varlink *v) {
    1667                 :            :         int r;
    1668                 :            : 
    1669         [ -  + ]:        524 :         assert(v);
    1670                 :            : 
    1671         [ +  - ]:        524 :         if (v->ucred_acquired)
    1672                 :        524 :                 return 0;
    1673                 :            : 
    1674                 :          0 :         r = getpeercred(v->fd, &v->ucred);
    1675         [ #  # ]:          0 :         if (r < 0)
    1676                 :          0 :                 return r;
    1677                 :            : 
    1678                 :          0 :         v->ucred_acquired = true;
    1679                 :          0 :         return 0;
    1680                 :            : }
    1681                 :            : 
    1682                 :        524 : int varlink_get_peer_uid(Varlink *v, uid_t *ret) {
    1683                 :            :         int r;
    1684                 :            : 
    1685   [ -  +  -  + ]:        524 :         assert_return(v, -EINVAL);
    1686   [ -  +  -  + ]:        524 :         assert_return(ret, -EINVAL);
    1687                 :            : 
    1688                 :        524 :         r = varlink_acquire_ucred(v);
    1689         [ -  + ]:        524 :         if (r < 0)
    1690                 :          0 :                 return r;
    1691                 :            : 
    1692         [ -  + ]:        524 :         if (!uid_is_valid(v->ucred.uid))
    1693                 :          0 :                 return -ENODATA;
    1694                 :            : 
    1695                 :        524 :         *ret = v->ucred.uid;
    1696                 :        524 :         return 0;
    1697                 :            : }
    1698                 :            : 
    1699                 :          0 : int varlink_get_peer_pid(Varlink *v, pid_t *ret) {
    1700                 :            :         int r;
    1701                 :            : 
    1702   [ #  #  #  # ]:          0 :         assert_return(v, -EINVAL);
    1703   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
    1704                 :            : 
    1705                 :          0 :         r = varlink_acquire_ucred(v);
    1706         [ #  # ]:          0 :         if (r < 0)
    1707                 :          0 :                 return r;
    1708                 :            : 
    1709         [ #  # ]:          0 :         if (!pid_is_valid(v->ucred.pid))
    1710                 :          0 :                 return -ENODATA;
    1711                 :            : 
    1712                 :          0 :         *ret = v->ucred.pid;
    1713                 :          0 :         return 0;
    1714                 :            : }
    1715                 :            : 
    1716                 :          0 : int varlink_set_relative_timeout(Varlink *v, usec_t timeout) {
    1717   [ #  #  #  # ]:          0 :         assert_return(v, -EINVAL);
    1718   [ #  #  #  # ]:          0 :         assert_return(timeout > 0, -EINVAL);
    1719                 :            : 
    1720                 :          0 :         v->timeout = timeout;
    1721                 :          0 :         return 0;
    1722                 :            : }
    1723                 :            : 
    1724                 :          0 : VarlinkServer *varlink_get_server(Varlink *v) {
    1725   [ #  #  #  # ]:          0 :         assert_return(v, NULL);
    1726                 :            : 
    1727                 :          0 :         return v->server;
    1728                 :            : }
    1729                 :            : 
    1730                 :       1344 : int varlink_set_description(Varlink *v, const char *description) {
    1731   [ -  +  -  + ]:       1344 :         assert_return(v, -EINVAL);
    1732                 :            : 
    1733                 :       1344 :         return free_and_strdup(&v->description, description);
    1734                 :            : }
    1735                 :            : 
    1736                 :       1629 : static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
    1737                 :       1629 :         Varlink *v = userdata;
    1738                 :            : 
    1739         [ -  + ]:       1629 :         assert(s);
    1740         [ -  + ]:       1629 :         assert(v);
    1741                 :            : 
    1742                 :       1629 :         handle_revents(v, revents);
    1743                 :       1629 :         (void) varlink_process(v);
    1744                 :            : 
    1745                 :       1629 :         return 1;
    1746                 :            : }
    1747                 :            : 
    1748                 :          0 : static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
    1749                 :          0 :         Varlink *v = userdata;
    1750                 :            : 
    1751         [ #  # ]:          0 :         assert(s);
    1752         [ #  # ]:          0 :         assert(v);
    1753                 :            : 
    1754                 :          0 :         (void) varlink_process(v);
    1755                 :          0 :         return 1;
    1756                 :            : }
    1757                 :            : 
    1758                 :       5686 : static int defer_callback(sd_event_source *s, void *userdata) {
    1759                 :       5686 :         Varlink *v = userdata;
    1760                 :            : 
    1761         [ -  + ]:       5686 :         assert(s);
    1762         [ -  + ]:       5686 :         assert(v);
    1763                 :            : 
    1764                 :       5686 :         (void) varlink_process(v);
    1765                 :       5686 :         return 1;
    1766                 :            : }
    1767                 :            : 
    1768                 :    1435591 : static int prepare_callback(sd_event_source *s, void *userdata) {
    1769                 :    1435591 :         Varlink *v = userdata;
    1770                 :            :         int r, e;
    1771                 :            :         usec_t until;
    1772                 :            : 
    1773         [ -  + ]:    1435591 :         assert(s);
    1774         [ -  + ]:    1435591 :         assert(v);
    1775                 :            : 
    1776                 :    1435591 :         e = varlink_get_events(v);
    1777         [ -  + ]:    1435591 :         if (e < 0)
    1778                 :          0 :                 return e;
    1779                 :            : 
    1780                 :    1435591 :         r = sd_event_source_set_io_events(v->io_event_source, e);
    1781         [ -  + ]:    1435591 :         if (r < 0)
    1782                 :          0 :                 return r;
    1783                 :            : 
    1784                 :    1435591 :         r = varlink_get_timeout(v, &until);
    1785         [ -  + ]:    1435591 :         if (r < 0)
    1786                 :          0 :                 return r;
    1787         [ +  + ]:    1435591 :         if (r > 0) {
    1788                 :       4356 :                 r = sd_event_source_set_time(v->time_event_source, until);
    1789         [ -  + ]:       4356 :                 if (r < 0)
    1790                 :          0 :                         return r;
    1791                 :            :         }
    1792                 :            : 
    1793                 :    1435591 :         r = sd_event_source_set_enabled(v->time_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF);
    1794         [ -  + ]:    1435591 :         if (r < 0)
    1795                 :          0 :                 return r;
    1796                 :            : 
    1797                 :    1435591 :         return 1;
    1798                 :            : }
    1799                 :            : 
    1800                 :        763 : static int quit_callback(sd_event_source *event, void *userdata) {
    1801                 :        763 :         Varlink *v = userdata;
    1802                 :            : 
    1803         [ -  + ]:        763 :         assert(event);
    1804         [ -  + ]:        763 :         assert(v);
    1805                 :            : 
    1806                 :        763 :         varlink_flush(v);
    1807                 :        763 :         varlink_close(v);
    1808                 :            : 
    1809                 :        763 :         return 1;
    1810                 :            : }
    1811                 :            : 
    1812                 :       1864 : int varlink_attach_event(Varlink *v, sd_event *e, int64_t priority) {
    1813                 :            :         int r;
    1814                 :            : 
    1815   [ -  +  -  + ]:       1864 :         assert_return(v, -EINVAL);
    1816   [ -  +  -  + ]:       1864 :         assert_return(!v->event, -EBUSY);
    1817                 :            : 
    1818         [ +  - ]:       1864 :         if (e)
    1819                 :       1864 :                 v->event = sd_event_ref(e);
    1820                 :            :         else {
    1821                 :          0 :                 r = sd_event_default(&v->event);
    1822         [ #  # ]:          0 :                 if (r < 0)
    1823                 :          0 :                         return r;
    1824                 :            :         }
    1825                 :            : 
    1826                 :       1864 :         r = sd_event_add_time(v->event, &v->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, v);
    1827         [ -  + ]:       1864 :         if (r < 0)
    1828                 :          0 :                 goto fail;
    1829                 :            : 
    1830                 :       1864 :         r = sd_event_source_set_priority(v->time_event_source, priority);
    1831         [ -  + ]:       1864 :         if (r < 0)
    1832                 :          0 :                 goto fail;
    1833                 :            : 
    1834                 :       1864 :         (void) sd_event_source_set_description(v->time_event_source, "varlink-time");
    1835                 :            : 
    1836                 :       1864 :         r = sd_event_add_exit(v->event, &v->quit_event_source, quit_callback, v);
    1837         [ -  + ]:       1864 :         if (r < 0)
    1838                 :          0 :                 goto fail;
    1839                 :            : 
    1840                 :       1864 :         r = sd_event_source_set_priority(v->quit_event_source, priority);
    1841         [ -  + ]:       1864 :         if (r < 0)
    1842                 :          0 :                 goto fail;
    1843                 :            : 
    1844                 :       1864 :         (void) sd_event_source_set_description(v->quit_event_source, "varlink-quit");
    1845                 :            : 
    1846                 :       1864 :         r = sd_event_add_io(v->event, &v->io_event_source, v->fd, 0, io_callback, v);
    1847         [ -  + ]:       1864 :         if (r < 0)
    1848                 :          0 :                 goto fail;
    1849                 :            : 
    1850                 :       1864 :         r = sd_event_source_set_prepare(v->io_event_source, prepare_callback);
    1851         [ -  + ]:       1864 :         if (r < 0)
    1852                 :          0 :                 goto fail;
    1853                 :            : 
    1854                 :       1864 :         r = sd_event_source_set_priority(v->io_event_source, priority);
    1855         [ -  + ]:       1864 :         if (r < 0)
    1856                 :          0 :                 goto fail;
    1857                 :            : 
    1858                 :       1864 :         (void) sd_event_source_set_description(v->io_event_source, "varlink-io");
    1859                 :            : 
    1860                 :       1864 :         r = sd_event_add_defer(v->event, &v->defer_event_source, defer_callback, v);
    1861         [ -  + ]:       1864 :         if (r < 0)
    1862                 :          0 :                 goto fail;
    1863                 :            : 
    1864                 :       1864 :         r = sd_event_source_set_priority(v->defer_event_source, priority);
    1865         [ -  + ]:       1864 :         if (r < 0)
    1866                 :          0 :                 goto fail;
    1867                 :            : 
    1868                 :       1864 :         (void) sd_event_source_set_description(v->defer_event_source, "varlink-defer");
    1869                 :            : 
    1870                 :       1864 :         return 0;
    1871                 :            : 
    1872                 :          0 : fail:
    1873                 :          0 :         varlink_detach_event(v);
    1874                 :          0 :         return r;
    1875                 :            : }
    1876                 :            : 
    1877                 :          0 : void varlink_detach_event(Varlink *v) {
    1878         [ #  # ]:          0 :         if (!v)
    1879                 :          0 :                 return;
    1880                 :            : 
    1881                 :          0 :         varlink_detach_event_sources(v);
    1882                 :            : 
    1883                 :          0 :         v->event = sd_event_unref(v->event);
    1884                 :            : }
    1885                 :            : 
    1886                 :          8 : sd_event *varlink_get_event(Varlink *v) {
    1887   [ -  +  -  + ]:          8 :         assert_return(v, NULL);
    1888                 :            : 
    1889                 :          8 :         return v->event;
    1890                 :            : }
    1891                 :            : 
    1892                 :          4 : int varlink_server_new(VarlinkServer **ret, VarlinkServerFlags flags) {
    1893                 :            :         VarlinkServer *s;
    1894                 :            : 
    1895   [ -  +  -  + ]:          4 :         assert_return(ret, -EINVAL);
    1896   [ -  +  -  + ]:          4 :         assert_return((flags & ~_VARLINK_SERVER_FLAGS_ALL) == 0, -EINVAL);
    1897                 :            : 
    1898                 :          4 :         s = new(VarlinkServer, 1);
    1899         [ -  + ]:          4 :         if (!s)
    1900                 :          0 :                 return -ENOMEM;
    1901                 :            : 
    1902                 :          4 :         *s = (VarlinkServer) {
    1903                 :            :                 .n_ref = 1,
    1904                 :            :                 .flags = flags,
    1905                 :          4 :                 .connections_max = varlink_server_connections_max(NULL),
    1906                 :          4 :                 .connections_per_uid_max = varlink_server_connections_per_uid_max(NULL),
    1907                 :            :         };
    1908                 :            : 
    1909                 :          4 :         *ret = s;
    1910                 :          4 :         return 0;
    1911                 :            : }
    1912                 :            : 
    1913                 :          4 : static VarlinkServer* varlink_server_destroy(VarlinkServer *s) {
    1914                 :            :         char *m;
    1915                 :            : 
    1916         [ -  + ]:          4 :         if (!s)
    1917                 :          0 :                 return NULL;
    1918                 :            : 
    1919                 :          4 :         varlink_server_shutdown(s);
    1920                 :            : 
    1921         [ +  + ]:         12 :         while ((m = hashmap_steal_first_key(s->methods)))
    1922                 :          8 :                 free(m);
    1923                 :            : 
    1924                 :          4 :         hashmap_free(s->methods);
    1925                 :          4 :         hashmap_free(s->by_uid);
    1926                 :            : 
    1927                 :          4 :         sd_event_unref(s->event);
    1928                 :            : 
    1929                 :          4 :         free(s->description);
    1930                 :            : 
    1931                 :          4 :         return mfree(s);
    1932                 :            : }
    1933                 :            : 
    1934   [ -  +  -  +  :       1052 : DEFINE_TRIVIAL_REF_UNREF_FUNC(VarlinkServer, varlink_server, varlink_server_destroy);
                   +  + ]
    1935                 :            : 
    1936                 :        524 : static int validate_connection(VarlinkServer *server, const struct ucred *ucred) {
    1937                 :        524 :         int allowed = -1;
    1938                 :            : 
    1939         [ -  + ]:        524 :         assert(server);
    1940         [ -  + ]:        524 :         assert(ucred);
    1941                 :            : 
    1942         [ -  + ]:        524 :         if (FLAGS_SET(server->flags, VARLINK_SERVER_ROOT_ONLY))
    1943                 :          0 :                 allowed = ucred->uid == 0;
    1944                 :            : 
    1945         [ -  + ]:        524 :         if (FLAGS_SET(server->flags, VARLINK_SERVER_MYSELF_ONLY))
    1946   [ #  #  #  # ]:          0 :                 allowed = allowed > 0 || ucred->uid == getuid();
    1947                 :            : 
    1948         [ -  + ]:        524 :         if (allowed == 0) { /* Allow access when it is explicitly allowed or when neither
    1949                 :            :                              * VARLINK_SERVER_ROOT_ONLY nor VARLINK_SERVER_MYSELF_ONLY are specified. */
    1950         [ #  # ]:          0 :                 varlink_server_log(server, "Unprivileged client attempted connection, refusing.");
    1951                 :          0 :                 return 0;
    1952                 :            :         }
    1953                 :            : 
    1954         [ -  + ]:        524 :         if (server->n_connections >= server->connections_max) {
    1955         [ #  # ]:          0 :                 varlink_server_log(server, "Connection limit of %u reached, refusing.", server->connections_max);
    1956                 :          0 :                 return 0;
    1957                 :            :         }
    1958                 :            : 
    1959         [ +  - ]:        524 :         if (FLAGS_SET(server->flags, VARLINK_SERVER_ACCOUNT_UID)) {
    1960                 :            :                 unsigned c;
    1961                 :            : 
    1962         [ -  + ]:        524 :                 if (!uid_is_valid(ucred->uid)) {
    1963         [ #  # ]:          0 :                         varlink_server_log(server, "Client with invalid UID attempted connection, refusing.");
    1964                 :          0 :                         return 0;
    1965                 :            :                 }
    1966                 :            : 
    1967                 :        524 :                 c = PTR_TO_UINT(hashmap_get(server->by_uid, UID_TO_PTR(ucred->uid)));
    1968         [ -  + ]:        524 :                 if (c >= server->connections_per_uid_max) {
    1969         [ #  # ]:          0 :                         varlink_server_log(server, "Per-UID connection limit of %u reached, refusing.",
    1970                 :            :                                            server->connections_per_uid_max);
    1971                 :          0 :                         return 0;
    1972                 :            :                 }
    1973                 :            :         }
    1974                 :            : 
    1975                 :        524 :         return 1;
    1976                 :            : }
    1977                 :            : 
    1978                 :        524 : static int count_connection(VarlinkServer *server, struct ucred *ucred) {
    1979                 :            :         unsigned c;
    1980                 :            :         int r;
    1981                 :            : 
    1982         [ -  + ]:        524 :         assert(server);
    1983         [ -  + ]:        524 :         assert(ucred);
    1984                 :            : 
    1985                 :        524 :         server->n_connections++;
    1986                 :            : 
    1987         [ +  - ]:        524 :         if (FLAGS_SET(server->flags, VARLINK_SERVER_ACCOUNT_UID)) {
    1988                 :        524 :                 r = hashmap_ensure_allocated(&server->by_uid, NULL);
    1989         [ -  + ]:        524 :                 if (r < 0)
    1990         [ #  # ]:          0 :                         return log_debug_errno(r, "Failed to allocate UID hash table: %m");
    1991                 :            : 
    1992                 :        524 :                 c = PTR_TO_UINT(hashmap_get(server->by_uid, UID_TO_PTR(ucred->uid)));
    1993                 :            : 
    1994         [ +  - ]:        524 :                 varlink_server_log(server, "Connections of user " UID_FMT ": %u (of %u max)",
    1995                 :            :                                    ucred->uid, c, server->connections_per_uid_max);
    1996                 :            : 
    1997                 :        524 :                 r = hashmap_replace(server->by_uid, UID_TO_PTR(ucred->uid), UINT_TO_PTR(c + 1));
    1998         [ -  + ]:        524 :                 if (r < 0)
    1999         [ #  # ]:          0 :                         return log_debug_errno(r, "Failed to increment counter in UID hash table: %m");
    2000                 :            :         }
    2001                 :            : 
    2002                 :        524 :         return 0;
    2003                 :            : }
    2004                 :            : 
    2005                 :        524 : int varlink_server_add_connection(VarlinkServer *server, int fd, Varlink **ret) {
    2006                 :        524 :         _cleanup_(varlink_unrefp) Varlink *v = NULL;
    2007                 :            :         bool ucred_acquired;
    2008                 :            :         struct ucred ucred;
    2009                 :            :         int r;
    2010                 :            : 
    2011   [ -  +  -  + ]:        524 :         assert_return(server, -EINVAL);
    2012   [ -  +  -  + ]:        524 :         assert_return(fd >= 0, -EBADF);
    2013                 :            : 
    2014         [ +  - ]:        524 :         if ((server->flags & (VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_ACCOUNT_UID)) != 0) {
    2015                 :        524 :                 r = getpeercred(fd, &ucred);
    2016         [ -  + ]:        524 :                 if (r < 0)
    2017         [ #  # ]:          0 :                         return varlink_server_log_errno(server, r, "Failed to acquire peer credentials of incoming socket, refusing: %m");
    2018                 :            : 
    2019                 :        524 :                 ucred_acquired = true;
    2020                 :            : 
    2021                 :        524 :                 r = validate_connection(server, &ucred);
    2022         [ -  + ]:        524 :                 if (r < 0)
    2023                 :          0 :                         return r;
    2024         [ -  + ]:        524 :                 if (r == 0)
    2025                 :          0 :                         return -EPERM;
    2026                 :            :         } else
    2027                 :          0 :                 ucred_acquired = false;
    2028                 :            : 
    2029                 :        524 :         r = varlink_new(&v);
    2030         [ -  + ]:        524 :         if (r < 0)
    2031         [ #  # ]:          0 :                 return varlink_server_log_errno(server, r, "Failed to allocate connection object: %m");
    2032                 :            : 
    2033                 :        524 :         r = count_connection(server, &ucred);
    2034         [ -  + ]:        524 :         if (r < 0)
    2035                 :          0 :                 return r;
    2036                 :            : 
    2037                 :        524 :         v->fd = fd;
    2038                 :        524 :         v->userdata = server->userdata;
    2039         [ +  - ]:        524 :         if (ucred_acquired) {
    2040                 :        524 :                 v->ucred = ucred;
    2041                 :        524 :                 v->ucred_acquired = true;
    2042                 :            :         }
    2043                 :            : 
    2044         [ +  - ]:        524 :         (void) asprintf(&v->description, "%s-%i", server->description ?: "varlink", v->fd);
    2045                 :            : 
    2046                 :            :         /* Link up the server and the connection, and take reference in both directions. Note that the
    2047                 :            :          * reference on the connection is left dangling. It will be dropped when the connection is closed,
    2048                 :            :          * which happens in varlink_close(), including in the event loop quit callback. */
    2049                 :        524 :         v->server = varlink_server_ref(server);
    2050                 :        524 :         varlink_ref(v);
    2051                 :            : 
    2052                 :        524 :         varlink_set_state(v, VARLINK_IDLE_SERVER);
    2053                 :            : 
    2054         [ +  - ]:        524 :         if (server->event) {
    2055                 :        524 :                 r = varlink_attach_event(v, server->event, server->event_priority);
    2056         [ -  + ]:        524 :                 if (r < 0) {
    2057         [ #  # ]:          0 :                         varlink_log_errno(v, r, "Failed to attach new connection: %m");
    2058                 :          0 :                         v->fd = -1; /* take the fd out of the connection again */
    2059                 :          0 :                         varlink_close(v);
    2060                 :          0 :                         return r;
    2061                 :            :                 }
    2062                 :            :         }
    2063                 :            : 
    2064         [ +  - ]:        524 :         if (ret)
    2065                 :        524 :                 *ret = v;
    2066                 :            : 
    2067                 :        524 :         return 0;
    2068                 :            : }
    2069                 :            : 
    2070                 :        524 : static int connect_callback(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
    2071                 :        524 :         VarlinkServerSocket *ss = userdata;
    2072                 :        524 :         _cleanup_close_ int cfd = -1;
    2073                 :        524 :         Varlink *v = NULL;
    2074                 :            :         int r;
    2075                 :            : 
    2076         [ -  + ]:        524 :         assert(source);
    2077         [ -  + ]:        524 :         assert(ss);
    2078                 :            : 
    2079         [ +  - ]:        524 :         varlink_server_log(ss->server, "New incoming connection.");
    2080                 :            : 
    2081                 :        524 :         cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
    2082         [ -  + ]:        524 :         if (cfd < 0) {
    2083         [ #  # ]:          0 :                 if (ERRNO_IS_ACCEPT_AGAIN(errno))
    2084                 :          0 :                         return 0;
    2085                 :            : 
    2086         [ #  # ]:          0 :                 return varlink_server_log_errno(ss->server, errno, "Failed to accept incoming socket: %m");
    2087                 :            :         }
    2088                 :            : 
    2089                 :        524 :         r = varlink_server_add_connection(ss->server, cfd, &v);
    2090         [ -  + ]:        524 :         if (r < 0)
    2091                 :          0 :                 return 0;
    2092                 :            : 
    2093                 :        524 :         TAKE_FD(cfd);
    2094                 :            : 
    2095         [ +  - ]:        524 :         if (ss->server->connect_callback) {
    2096                 :        524 :                 r = ss->server->connect_callback(ss->server, v, ss->server->userdata);
    2097         [ -  + ]:        524 :                 if (r < 0) {
    2098         [ #  # ]:          0 :                         varlink_log_errno(v, r, "Connection callback returned error, disconnecting client: %m");
    2099                 :          0 :                         varlink_close(v);
    2100                 :          0 :                         return 0;
    2101                 :            :                 }
    2102                 :            :         }
    2103                 :            : 
    2104                 :        524 :         return 0;
    2105                 :            : }
    2106                 :            : 
    2107                 :          4 : int varlink_server_listen_fd(VarlinkServer *s, int fd) {
    2108                 :          4 :         _cleanup_free_ VarlinkServerSocket *ss = NULL;
    2109                 :            :         int r;
    2110                 :            : 
    2111   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2112   [ -  +  -  + ]:          4 :         assert_return(fd >= 0, -EBADF);
    2113                 :            : 
    2114                 :          4 :         r = fd_nonblock(fd, true);
    2115         [ -  + ]:          4 :         if (r < 0)
    2116                 :          0 :                 return r;
    2117                 :            : 
    2118                 :          4 :         ss = new(VarlinkServerSocket, 1);
    2119         [ -  + ]:          4 :         if (!ss)
    2120                 :          0 :                 return -ENOMEM;
    2121                 :            : 
    2122                 :          4 :         *ss = (VarlinkServerSocket) {
    2123                 :            :                 .server = s,
    2124                 :            :                 .fd = fd,
    2125                 :            :         };
    2126                 :            : 
    2127         [ -  + ]:          4 :         if (s->event) {
    2128         [ #  # ]:          0 :                 _cleanup_(sd_event_source_unrefp) sd_event_source *es = NULL;
    2129                 :            : 
    2130                 :          0 :                 r = sd_event_add_io(s->event, &es, fd, EPOLLIN, connect_callback, ss);
    2131         [ #  # ]:          0 :                 if (r < 0)
    2132                 :          0 :                         return r;
    2133                 :            : 
    2134                 :          0 :                 r = sd_event_source_set_priority(ss->event_source, s->event_priority);
    2135         [ #  # ]:          0 :                 if (r < 0)
    2136                 :          0 :                         return r;
    2137                 :            :         }
    2138                 :            : 
    2139   [ -  +  -  + ]:          4 :         LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss));
    2140                 :          4 :         return 0;
    2141                 :            : }
    2142                 :            : 
    2143                 :          4 : int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t m) {
    2144                 :            :         union sockaddr_union sockaddr;
    2145                 :          4 :         _cleanup_close_ int fd = -1;
    2146                 :            :         int r;
    2147                 :            : 
    2148   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2149   [ -  +  -  + ]:          4 :         assert_return(address, -EINVAL);
    2150   [ -  +  -  + ]:          4 :         assert_return((m & ~0777) == 0, -EINVAL);
    2151                 :            : 
    2152                 :          4 :         r = sockaddr_un_set_path(&sockaddr.un, address);
    2153         [ -  + ]:          4 :         if (r < 0)
    2154                 :          0 :                 return r;
    2155                 :            : 
    2156                 :          4 :         fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
    2157         [ -  + ]:          4 :         if (fd < 0)
    2158                 :          0 :                 return -errno;
    2159                 :            : 
    2160                 :          4 :         (void) sockaddr_un_unlink(&sockaddr.un);
    2161                 :            : 
    2162   [ +  +  +  - ]:          8 :         RUN_WITH_UMASK(~m & 0777)
    2163   [ -  +  -  +  :          4 :                 if (bind(fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0)
                   -  + ]
    2164                 :          0 :                         return -errno;
    2165                 :            : 
    2166         [ -  + ]:          4 :         if (listen(fd, SOMAXCONN) < 0)
    2167                 :          0 :                 return -errno;
    2168                 :            : 
    2169                 :          4 :         r = varlink_server_listen_fd(s, fd);
    2170         [ -  + ]:          4 :         if (r < 0)
    2171                 :          0 :                 return r;
    2172                 :            : 
    2173                 :          4 :         TAKE_FD(fd);
    2174                 :          4 :         return 0;
    2175                 :            : }
    2176                 :            : 
    2177                 :          0 : void* varlink_server_set_userdata(VarlinkServer *s, void *userdata) {
    2178                 :            :         void *ret;
    2179                 :            : 
    2180   [ #  #  #  # ]:          0 :         assert_return(s, NULL);
    2181                 :            : 
    2182                 :          0 :         ret = s->userdata;
    2183                 :          0 :         s->userdata = userdata;
    2184                 :            : 
    2185                 :          0 :         return ret;
    2186                 :            : }
    2187                 :            : 
    2188                 :          0 : void* varlink_server_get_userdata(VarlinkServer *s) {
    2189   [ #  #  #  # ]:          0 :         assert_return(s, NULL);
    2190                 :            : 
    2191                 :          0 :         return s->userdata;
    2192                 :            : }
    2193                 :            : 
    2194                 :          4 : static VarlinkServerSocket* varlink_server_socket_destroy(VarlinkServerSocket *ss) {
    2195         [ -  + ]:          4 :         if (!ss)
    2196                 :          0 :                 return NULL;
    2197                 :            : 
    2198         [ +  - ]:          4 :         if (ss->server)
    2199   [ -  +  -  +  :          4 :                 LIST_REMOVE(sockets, ss->server->sockets, ss);
             -  +  -  + ]
    2200                 :            : 
    2201                 :          4 :         sd_event_source_disable_unref(ss->event_source);
    2202                 :            : 
    2203                 :          4 :         free(ss->address);
    2204                 :          4 :         safe_close(ss->fd);
    2205                 :            : 
    2206                 :          4 :         return mfree(ss);
    2207                 :            : }
    2208                 :            : 
    2209                 :          4 : int varlink_server_shutdown(VarlinkServer *s) {
    2210   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2211                 :            : 
    2212         [ +  + ]:          8 :         while (s->sockets)
    2213                 :          4 :                 varlink_server_socket_destroy(s->sockets);
    2214                 :            : 
    2215                 :          4 :         return 0;
    2216                 :            : }
    2217                 :            : 
    2218                 :          4 : int varlink_server_attach_event(VarlinkServer *s, sd_event *e, int64_t priority) {
    2219                 :            :         VarlinkServerSocket *ss;
    2220                 :            :         int r;
    2221                 :            : 
    2222   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2223   [ -  +  -  + ]:          4 :         assert_return(!s->event, -EBUSY);
    2224                 :            : 
    2225         [ +  - ]:          4 :         if (e)
    2226                 :          4 :                 s->event = sd_event_ref(e);
    2227                 :            :         else {
    2228                 :          0 :                 r = sd_event_default(&s->event);
    2229         [ #  # ]:          0 :                 if (r < 0)
    2230                 :          0 :                         return r;
    2231                 :            :         }
    2232                 :            : 
    2233         [ +  + ]:          8 :         LIST_FOREACH(sockets, ss, s->sockets) {
    2234         [ -  + ]:          4 :                 assert(!ss->event_source);
    2235                 :            : 
    2236                 :          4 :                 r = sd_event_add_io(s->event, &ss->event_source, ss->fd, EPOLLIN, connect_callback, ss);
    2237         [ -  + ]:          4 :                 if (r < 0)
    2238                 :          0 :                         goto fail;
    2239                 :            : 
    2240                 :          4 :                 r = sd_event_source_set_priority(ss->event_source, priority);
    2241         [ -  + ]:          4 :                 if (r < 0)
    2242                 :          0 :                         goto fail;
    2243                 :            :         }
    2244                 :            : 
    2245                 :          4 :         s->event_priority = priority;
    2246                 :          4 :         return 0;
    2247                 :            : 
    2248                 :          0 : fail:
    2249                 :          0 :         varlink_server_detach_event(s);
    2250                 :          0 :         return r;
    2251                 :            : }
    2252                 :            : 
    2253                 :          0 : int varlink_server_detach_event(VarlinkServer *s) {
    2254                 :            :         VarlinkServerSocket *ss;
    2255                 :            : 
    2256   [ #  #  #  # ]:          0 :         assert_return(s, -EINVAL);
    2257                 :            : 
    2258         [ #  # ]:          0 :         LIST_FOREACH(sockets, ss, s->sockets) {
    2259                 :            : 
    2260         [ #  # ]:          0 :                 if (!ss->event_source)
    2261                 :          0 :                         continue;
    2262                 :            : 
    2263                 :          0 :                 (void) sd_event_source_set_enabled(ss->event_source, SD_EVENT_OFF);
    2264                 :          0 :                 ss->event_source = sd_event_source_unref(ss->event_source);
    2265                 :            :         }
    2266                 :            : 
    2267                 :          0 :         sd_event_unref(s->event);
    2268                 :          0 :         return 0;
    2269                 :            : }
    2270                 :            : 
    2271                 :          0 : sd_event *varlink_server_get_event(VarlinkServer *s) {
    2272   [ #  #  #  # ]:          0 :         assert_return(s, NULL);
    2273                 :            : 
    2274                 :          0 :         return s->event;
    2275                 :            : }
    2276                 :            : 
    2277                 :          8 : int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMethod callback) {
    2278                 :            :         char *m;
    2279                 :            :         int r;
    2280                 :            : 
    2281   [ -  +  -  + ]:          8 :         assert_return(s, -EINVAL);
    2282   [ -  +  -  + ]:          8 :         assert_return(method, -EINVAL);
    2283   [ -  +  -  + ]:          8 :         assert_return(callback, -EINVAL);
    2284                 :            : 
    2285         [ -  + ]:          8 :         if (startswith(method, "org.varlink.service."))
    2286                 :          0 :                 return -EEXIST;
    2287                 :            : 
    2288                 :          8 :         r = hashmap_ensure_allocated(&s->methods, &string_hash_ops);
    2289         [ -  + ]:          8 :         if (r < 0)
    2290                 :          0 :                 return r;
    2291                 :            : 
    2292                 :          8 :         m = strdup(method);
    2293         [ -  + ]:          8 :         if (!m)
    2294                 :          0 :                 return -ENOMEM;
    2295                 :            : 
    2296                 :          8 :         r = hashmap_put(s->methods, m, callback);
    2297         [ -  + ]:          8 :         if (r < 0) {
    2298                 :          0 :                 free(m);
    2299                 :          0 :                 return r;
    2300                 :            :         }
    2301                 :            : 
    2302                 :          8 :         return 0;
    2303                 :            : }
    2304                 :            : 
    2305                 :          0 : int varlink_server_bind_method_many_internal(VarlinkServer *s, ...) {
    2306                 :            :         va_list ap;
    2307                 :          0 :         int r = 0;
    2308                 :            : 
    2309   [ #  #  #  # ]:          0 :         assert_return(s, -EINVAL);
    2310                 :            : 
    2311                 :          0 :         va_start(ap, s);
    2312                 :          0 :         for (;;) {
    2313                 :            :                 VarlinkMethod callback;
    2314                 :            :                 const char *method;
    2315                 :            : 
    2316                 :          0 :                 method = va_arg(ap, const char *);
    2317         [ #  # ]:          0 :                 if (!method)
    2318                 :          0 :                         break;
    2319                 :            : 
    2320                 :          0 :                 callback = va_arg(ap, VarlinkMethod);
    2321                 :            : 
    2322                 :          0 :                 r = varlink_server_bind_method(s, method, callback);
    2323         [ #  # ]:          0 :                 if (r < 0)
    2324                 :          0 :                         break;
    2325                 :            :         }
    2326                 :          0 :         va_end(ap);
    2327                 :            : 
    2328                 :          0 :         return r;
    2329                 :            : }
    2330                 :            : 
    2331                 :          4 : int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) {
    2332   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2333                 :            : 
    2334   [ +  -  -  +  :          4 :         if (callback && s->connect_callback && callback != s->connect_callback)
                   #  # ]
    2335                 :          0 :                 return -EBUSY;
    2336                 :            : 
    2337                 :          4 :         s->connect_callback = callback;
    2338                 :          4 :         return 0;
    2339                 :            : }
    2340                 :            : 
    2341                 :          8 : unsigned varlink_server_connections_max(VarlinkServer *s) {
    2342                 :            :         struct rlimit rl;
    2343                 :            : 
    2344                 :            :         /* If a server is specified, return the setting for that server, otherwise the default value */
    2345         [ -  + ]:          8 :         if (s)
    2346                 :          0 :                 return s->connections_max;
    2347                 :            : 
    2348         [ -  + ]:          8 :         assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
    2349                 :            : 
    2350                 :            :         /* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */
    2351         [ +  - ]:          8 :         if (VARLINK_DEFAULT_CONNECTIONS_MAX > rl.rlim_cur / 4 * 3)
    2352                 :          8 :                 return rl.rlim_cur / 4 * 3;
    2353                 :            : 
    2354                 :          0 :         return VARLINK_DEFAULT_CONNECTIONS_MAX;
    2355                 :            : }
    2356                 :            : 
    2357                 :          4 : unsigned varlink_server_connections_per_uid_max(VarlinkServer *s) {
    2358                 :            :         unsigned m;
    2359                 :            : 
    2360         [ -  + ]:          4 :         if (s)
    2361                 :          0 :                 return s->connections_per_uid_max;
    2362                 :            : 
    2363                 :            :         /* Make sure to never use up more than ¾th of available connections for a single user */
    2364                 :          4 :         m = varlink_server_connections_max(NULL);
    2365         [ +  - ]:          4 :         if (VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX > m)
    2366                 :          4 :                 return m / 4 * 3;
    2367                 :            : 
    2368                 :          0 :         return VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX;
    2369                 :            : }
    2370                 :            : 
    2371                 :          0 : int varlink_server_set_connections_per_uid_max(VarlinkServer *s, unsigned m) {
    2372   [ #  #  #  # ]:          0 :         assert_return(s, -EINVAL);
    2373   [ #  #  #  # ]:          0 :         assert_return(m > 0, -EINVAL);
    2374                 :            : 
    2375                 :          0 :         s->connections_per_uid_max = m;
    2376                 :          0 :         return 0;
    2377                 :            : }
    2378                 :            : 
    2379                 :          4 : int varlink_server_set_connections_max(VarlinkServer *s, unsigned m) {
    2380   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2381   [ -  +  -  + ]:          4 :         assert_return(m > 0, -EINVAL);
    2382                 :            : 
    2383                 :          4 :         s->connections_max = m;
    2384                 :          4 :         return 0;
    2385                 :            : }
    2386                 :            : 
    2387                 :          4 : int varlink_server_set_description(VarlinkServer *s, const char *description) {
    2388   [ -  +  -  + ]:          4 :         assert_return(s, -EINVAL);
    2389                 :            : 
    2390                 :          4 :         return free_and_strdup(&s->description, description);
    2391                 :            : }

Generated by: LCOV version 1.14