LCOV - code coverage report
Current view: top level - test - test-varlink.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 119 123 96.7 %
Date: 2019-08-23 13:36:53 Functions: 9 9 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 79 150 52.7 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <fcntl.h>
       4                 :            : #include <poll.h>
       5                 :            : #include <pthread.h>
       6                 :            : 
       7                 :            : #include "sd-event.h"
       8                 :            : 
       9                 :            : #include "fd-util.h"
      10                 :            : #include "json.h"
      11                 :            : #include "rm-rf.h"
      12                 :            : #include "strv.h"
      13                 :            : #include "tmpfile-util.h"
      14                 :            : #include "user-util.h"
      15                 :            : #include "varlink.h"
      16                 :            : 
      17                 :            : /* Let's pick some high value, that is higher than the largest listen() backlog, but leaves enough room below
      18                 :            :    the typical RLIMIT_NOFILE value of 1024 so that we can process both sides of each socket in our
      19                 :            :    process. Or in other words: "OVERLOAD_CONNECTIONS * 2 + x < 1024" should hold, for some small x that
      20                 :            :    should cover any auxiliary fds, the listener server fds, stdin/stdout/stderr and whatever else. */
      21                 :            : #define OVERLOAD_CONNECTIONS 333
      22                 :            : 
      23                 :            : static int n_done = 0;
      24                 :            : static int block_write_fd = -1;
      25                 :            : 
      26                 :          8 : static int method_something(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
      27                 :          8 :         _cleanup_(json_variant_unrefp) JsonVariant *ret = NULL;
      28                 :            :         JsonVariant *a, *b;
      29                 :            :         intmax_t x, y;
      30                 :            :         int r;
      31                 :            : 
      32                 :          8 :         a = json_variant_by_key(parameters, "a");
      33         [ -  + ]:          8 :         if (!a)
      34                 :          0 :                 return varlink_error(link, "io.test.BadParameters", NULL);
      35                 :            : 
      36                 :          8 :         x = json_variant_integer(a);
      37                 :            : 
      38                 :          8 :         b = json_variant_by_key(parameters, "b");
      39         [ -  + ]:          8 :         if (!b)
      40                 :          0 :                 return varlink_error(link, "io.test.BadParameters", NULL);
      41                 :            : 
      42                 :          8 :         y = json_variant_integer(b);
      43                 :            : 
      44                 :          8 :         r = json_build(&ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("sum", JSON_BUILD_INTEGER(x + y))));
      45         [ -  + ]:          8 :         if (r < 0)
      46                 :          0 :                 return r;
      47                 :            : 
      48                 :          8 :         return varlink_reply(link, ret);
      49                 :            : }
      50                 :            : 
      51                 :          4 : static int method_done(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
      52                 :            : 
      53         [ +  - ]:          4 :         if (++n_done == 2)
      54                 :          4 :                 sd_event_exit(varlink_get_event(link), EXIT_FAILURE);
      55                 :            : 
      56                 :          4 :         return 0;
      57                 :            : }
      58                 :            : 
      59                 :          4 : static int reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
      60                 :            :         JsonVariant *sum;
      61                 :            : 
      62                 :          4 :         sum = json_variant_by_key(parameters, "sum");
      63                 :            : 
      64         [ -  + ]:          4 :         assert_se(json_variant_integer(sum) == 7+22);
      65                 :            : 
      66         [ -  + ]:          4 :         if (++n_done == 2)
      67                 :          0 :                 sd_event_exit(varlink_get_event(link), EXIT_FAILURE);
      68                 :            : 
      69                 :          4 :         return 0;
      70                 :            : }
      71                 :            : 
      72                 :        524 : static int on_connect(VarlinkServer *s, Varlink *link, void *userdata) {
      73                 :        524 :         uid_t uid = UID_INVALID;
      74                 :            : 
      75         [ -  + ]:        524 :         assert(s);
      76         [ -  + ]:        524 :         assert(link);
      77                 :            : 
      78         [ -  + ]:        524 :         assert_se(varlink_get_peer_uid(link, &uid) >= 0);
      79         [ -  + ]:        524 :         assert_se(getuid() == uid);
      80                 :            : 
      81                 :        524 :         return 0;
      82                 :            : }
      83                 :            : 
      84                 :          4 : static int overload_reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) {
      85                 :            : 
      86                 :            :         /* This method call reply should always be called with a disconnection, since the method call should
      87                 :            :          * be talking to an overloaded server */
      88                 :            : 
      89         [ +  - ]:          4 :         log_debug("Over reply triggered with error: %s", strna(error_id));
      90         [ -  + ]:          4 :         assert_se(streq(error_id, VARLINK_ERROR_DISCONNECTED));
      91                 :          4 :         sd_event_exit(varlink_get_event(link), 0);
      92                 :            : 
      93                 :          4 :         return 0;
      94                 :            : }
      95                 :            : 
      96                 :          4 : static void flood_test(const char *address) {
      97                 :          4 :         _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
      98                 :          4 :         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
      99                 :          4 :         _cleanup_free_ Varlink **connections = NULL;
     100                 :            :         size_t k;
     101                 :          4 :         char x = 'x';
     102                 :            : 
     103         [ +  - ]:          4 :         log_debug("Flooding server...");
     104                 :            : 
     105                 :            :         /* Block the main event loop while we flood */
     106         [ -  + ]:          4 :         assert_se(write(block_write_fd, &x, sizeof(x)) == sizeof(x));
     107                 :            : 
     108         [ -  + ]:          4 :         assert_se(sd_event_default(&e) >= 0);
     109                 :            : 
     110                 :            :         /* Flood the server with connections */
     111         [ -  + ]:          4 :         assert_se(connections = new0(Varlink*, OVERLOAD_CONNECTIONS));
     112         [ +  + ]:       1336 :         for (k = 0; k < OVERLOAD_CONNECTIONS; k++) {
     113                 :       1332 :                 _cleanup_free_ char *t = NULL;
     114         [ +  - ]:       1332 :                 log_debug("connection %zu", k);
     115         [ -  + ]:       1332 :                 assert_se(varlink_connect_address(connections + k, address) >= 0);
     116                 :            : 
     117         [ -  + ]:       1332 :                 assert_se(asprintf(&t, "flood-%zu", k) >= 0);
     118         [ -  + ]:       1332 :                 assert_se(varlink_set_description(connections[k], t) >= 0);
     119         [ -  + ]:       1332 :                 assert_se(varlink_attach_event(connections[k], e, k) >= 0);
     120         [ -  + ]:       1332 :                 assert_se(varlink_sendb(connections[k], "io.test.Rubbish", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("id", JSON_BUILD_INTEGER(k)))) >= 0);
     121                 :            :         }
     122                 :            : 
     123                 :            :         /* Then, create one more, which should fail */
     124         [ +  - ]:          4 :         log_debug("Creating overload connection...");
     125         [ -  + ]:          4 :         assert_se(varlink_connect_address(&c, address) >= 0);
     126         [ -  + ]:          4 :         assert_se(varlink_set_description(c, "overload-client") >= 0);
     127         [ -  + ]:          4 :         assert_se(varlink_attach_event(c, e, k) >= 0);
     128         [ -  + ]:          4 :         assert_se(varlink_bind_reply(c, overload_reply) >= 0);
     129         [ -  + ]:          4 :         assert_se(varlink_invokeb(c, "io.test.Overload", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("foo", JSON_BUILD_STRING("bar")))) >= 0);
     130                 :            : 
     131                 :            :         /* Unblock it */
     132         [ +  - ]:          4 :         log_debug("Unblocking server...");
     133                 :          4 :         block_write_fd = safe_close(block_write_fd);
     134                 :            : 
     135                 :            :         /* This loop will terminate as soon as the overload reply callback is called */
     136         [ -  + ]:          4 :         assert_se(sd_event_loop(e) >= 0);
     137                 :            : 
     138                 :            :         /* And close all connections again */
     139         [ +  + ]:       1336 :         for (k = 0; k < OVERLOAD_CONNECTIONS; k++)
     140                 :       1332 :                 connections[k] = varlink_unref(connections[k]);
     141                 :          4 : }
     142                 :            : 
     143                 :          4 : static void *thread(void *arg) {
     144                 :          4 :         _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
     145                 :          8 :         _cleanup_(json_variant_unrefp) JsonVariant *i = NULL;
     146                 :          4 :         JsonVariant *o = NULL;
     147                 :            :         const char *e;
     148                 :            : 
     149         [ -  + ]:          4 :         assert_se(json_build(&i, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_INTEGER(88)),
     150                 :            :                                                    JSON_BUILD_PAIR("b", JSON_BUILD_INTEGER(99)))) >= 0);
     151                 :            : 
     152         [ -  + ]:          4 :         assert_se(varlink_connect_address(&c, arg) >= 0);
     153         [ -  + ]:          4 :         assert_se(varlink_set_description(c, "thread-client") >= 0);
     154                 :            : 
     155         [ -  + ]:          4 :         assert_se(varlink_call(c, "io.test.DoSomething", i, &o, &e, NULL) >= 0);
     156         [ -  + ]:          4 :         assert_se(json_variant_integer(json_variant_by_key(o, "sum")) == 88 + 99);
     157         [ -  + ]:          4 :         assert_se(!e);
     158                 :            : 
     159         [ -  + ]:          4 :         assert_se(varlink_callb(c, "io.test.IDontExist", &o, &e, NULL, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_REAL(5.5)))) >= 0);
     160         [ -  + ]:          4 :         assert_se(streq_ptr(json_variant_string(json_variant_by_key(o, "method")), "io.test.IDontExist"));
     161         [ -  + ]:          4 :         assert_se(streq(e, VARLINK_ERROR_METHOD_NOT_FOUND));
     162                 :            : 
     163                 :          4 :         flood_test(arg);
     164                 :            : 
     165         [ -  + ]:          4 :         assert_se(varlink_send(c, "io.test.Done", NULL) >= 0);
     166                 :            : 
     167                 :          4 :         return NULL;
     168                 :            : }
     169                 :            : 
     170                 :          4 : static int block_fd_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     171                 :            :         char c;
     172                 :            : 
     173         [ -  + ]:          4 :         assert_se(fd_nonblock(fd, false) >= 0);
     174                 :            : 
     175         [ -  + ]:          4 :         assert_se(read(fd, &c, sizeof(c)) == sizeof(c));
     176                 :            :         /* When a character is written to this pipe we'll block until the pipe is closed. */
     177                 :            : 
     178         [ -  + ]:          4 :         assert_se(read(fd, &c, sizeof(c)) == 0);
     179                 :            : 
     180         [ -  + ]:          4 :         assert_se(fd_nonblock(fd, true) >= 0);
     181                 :            : 
     182         [ -  + ]:          4 :         assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
     183                 :            : 
     184                 :          4 :         return 0;
     185                 :            : }
     186                 :            : 
     187                 :          4 : int main(int argc, char *argv[]) {
     188                 :          4 :         _cleanup_(sd_event_source_unrefp) sd_event_source *block_event = NULL;
     189                 :          4 :         _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
     190                 :          4 :         _cleanup_(varlink_flush_close_unrefp) Varlink *c = NULL;
     191                 :          4 :         _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
     192                 :          4 :         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
     193                 :          4 :         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
     194                 :          8 :         _cleanup_(close_pairp) int block_fds[2] = { -1, -1 };
     195                 :            :         pthread_t t;
     196                 :            :         const char *sp;
     197                 :            : 
     198                 :          4 :         log_set_max_level(LOG_DEBUG);
     199                 :          4 :         log_open();
     200                 :            : 
     201         [ -  + ]:          4 :         assert_se(mkdtemp_malloc("/tmp/varlink-test-XXXXXX", &tmpdir) >= 0);
     202   [ +  +  +  -  :         20 :         sp = strjoina(tmpdir, "/socket");
          -  +  -  +  +  
                +  +  - ]
     203                 :            : 
     204         [ -  + ]:          4 :         assert_se(sd_event_default(&e) >= 0);
     205                 :            : 
     206         [ -  + ]:          4 :         assert_se(pipe2(block_fds, O_NONBLOCK|O_CLOEXEC) >= 0);
     207         [ -  + ]:          4 :         assert_se(sd_event_add_io(e, &block_event, block_fds[0], EPOLLIN, block_fd_handler, NULL) >= 0);
     208         [ -  + ]:          4 :         assert_se(sd_event_source_set_priority(block_event, SD_EVENT_PRIORITY_IMPORTANT) >= 0);
     209                 :          4 :         block_write_fd = TAKE_FD(block_fds[1]);
     210                 :            : 
     211         [ -  + ]:          4 :         assert_se(varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID) >= 0);
     212         [ -  + ]:          4 :         assert_se(varlink_server_set_description(s, "our-server") >= 0);
     213                 :            : 
     214         [ -  + ]:          4 :         assert_se(varlink_server_bind_method(s, "io.test.DoSomething", method_something) >= 0);
     215         [ -  + ]:          4 :         assert_se(varlink_server_bind_method(s, "io.test.Done", method_done) >= 0);
     216         [ -  + ]:          4 :         assert_se(varlink_server_bind_connect(s, on_connect) >= 0);
     217         [ -  + ]:          4 :         assert_se(varlink_server_listen_address(s, sp, 0600) >= 0);
     218         [ -  + ]:          4 :         assert_se(varlink_server_attach_event(s, e, 0) >= 0);
     219         [ -  + ]:          4 :         assert_se(varlink_server_set_connections_max(s, OVERLOAD_CONNECTIONS) >= 0);
     220                 :            : 
     221         [ -  + ]:          4 :         assert_se(varlink_connect_address(&c, sp) >= 0);
     222         [ -  + ]:          4 :         assert_se(varlink_set_description(c, "main-client") >= 0);
     223         [ -  + ]:          4 :         assert_se(varlink_bind_reply(c, reply) >= 0);
     224                 :            : 
     225         [ -  + ]:          4 :         assert_se(json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_INTEGER(7)),
     226                 :            :                                                    JSON_BUILD_PAIR("b", JSON_BUILD_INTEGER(22)))) >= 0);
     227                 :            : 
     228         [ -  + ]:          4 :         assert_se(varlink_invoke(c, "io.test.DoSomething", v) >= 0);
     229                 :            : 
     230         [ -  + ]:          4 :         assert_se(varlink_attach_event(c, e, 0) >= 0);
     231                 :            : 
     232         [ -  + ]:          4 :         assert_se(pthread_create(&t, NULL, thread, (void*) sp) == 0);
     233                 :            : 
     234         [ -  + ]:          4 :         assert_se(sd_event_loop(e) >= 0);
     235                 :            : 
     236         [ -  + ]:          4 :         assert_se(pthread_join(t, NULL) == 0);
     237                 :            : 
     238                 :          4 :         return 0;
     239                 :            : }

Generated by: LCOV version 1.14