LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - test-bus-chat.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 186 285 65.3 %
Date: 2019-08-22 15:41:25 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <fcntl.h>
       4             : #include <pthread.h>
       5             : #include <stdlib.h>
       6             : #include <unistd.h>
       7             : 
       8             : #include "sd-bus.h"
       9             : 
      10             : #include "alloc-util.h"
      11             : #include "bus-error.h"
      12             : #include "bus-internal.h"
      13             : #include "bus-match.h"
      14             : #include "bus-util.h"
      15             : #include "errno-util.h"
      16             : #include "fd-util.h"
      17             : #include "format-util.h"
      18             : #include "log.h"
      19             : #include "macro.h"
      20             : #include "tests.h"
      21             : #include "util.h"
      22             : 
      23          18 : static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
      24          18 :         log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
      25          18 :         return 0;
      26             : }
      27             : 
      28           1 : static int object_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
      29             :         int r;
      30             : 
      31           1 :         if (sd_bus_message_is_method_error(m, NULL))
      32           0 :                 return 0;
      33             : 
      34           1 :         if (sd_bus_message_is_method_call(m, "org.object.test", "Foobar")) {
      35           1 :                 log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m));
      36             : 
      37           1 :                 r = sd_bus_reply_method_return(m, NULL);
      38           1 :                 if (r < 0)
      39           0 :                         return log_error_errno(r, "Failed to send reply: %m");
      40             : 
      41           1 :                 return 1;
      42             :         }
      43             : 
      44           0 :         return 0;
      45             : }
      46             : 
      47           1 : static int server_init(sd_bus **_bus) {
      48           1 :         sd_bus *bus = NULL;
      49             :         sd_id128_t id;
      50             :         int r;
      51             :         const char *unique, *desc;
      52             : 
      53           1 :         assert_se(_bus);
      54             : 
      55           1 :         r = sd_bus_open_user_with_description(&bus, "my bus!");
      56           1 :         if (r < 0) {
      57           0 :                 log_error_errno(r, "Failed to connect to user bus: %m");
      58           0 :                 goto fail;
      59             :         }
      60             : 
      61           1 :         r = sd_bus_get_bus_id(bus, &id);
      62           1 :         if (r < 0) {
      63           0 :                 log_error_errno(r, "Failed to get server ID: %m");
      64           0 :                 goto fail;
      65             :         }
      66             : 
      67           1 :         r = sd_bus_get_unique_name(bus, &unique);
      68           1 :         if (r < 0) {
      69           0 :                 log_error_errno(r, "Failed to get unique name: %m");
      70           0 :                 goto fail;
      71             :         }
      72             : 
      73           1 :         r = sd_bus_get_description(bus, &desc);
      74           1 :         assert_se(streq(desc, "my bus!"));
      75             : 
      76           1 :         log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
      77           1 :         log_info("Unique ID: %s", unique);
      78           1 :         log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
      79             : 
      80           1 :         r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
      81           1 :         if (r < 0) {
      82           0 :                 log_error_errno(r, "Failed to acquire name: %m");
      83           0 :                 goto fail;
      84             :         }
      85             : 
      86           1 :         r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
      87           1 :         if (r < 0) {
      88           0 :                 log_error_errno(r, "Failed to add object: %m");
      89           0 :                 goto fail;
      90             :         }
      91             : 
      92           1 :         r = sd_bus_match_signal(bus, NULL, NULL, NULL, "foo.bar", "Notify", match_callback, NULL);
      93           1 :         if (r < 0) {
      94           0 :                 log_error_errno(r, "Failed to request match: %m");
      95           0 :                 goto fail;
      96             :         }
      97             : 
      98           1 :         r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
      99           1 :         if (r < 0) {
     100           0 :                 log_error_errno(r, "Failed to add match: %m");
     101           0 :                 goto fail;
     102             :         }
     103             : 
     104           1 :         bus_match_dump(&bus->match_callbacks, 0);
     105             : 
     106           1 :         *_bus = bus;
     107           1 :         return 0;
     108             : 
     109           0 : fail:
     110           0 :         sd_bus_unref(bus);
     111           0 :         return r;
     112             : }
     113             : 
     114           1 : static int server(sd_bus *bus) {
     115             :         int r;
     116           1 :         bool client1_gone = false, client2_gone = false;
     117             : 
     118          34 :         while (!client1_gone || !client2_gone) {
     119          33 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     120          33 :                 pid_t pid = 0;
     121          33 :                 const char *label = NULL;
     122             : 
     123          33 :                 r = sd_bus_process(bus, &m);
     124          33 :                 if (r < 0) {
     125           0 :                         log_error_errno(r, "Failed to process requests: %m");
     126           0 :                         goto fail;
     127             :                 }
     128             : 
     129          33 :                 if (r == 0) {
     130           5 :                         r = sd_bus_wait(bus, (uint64_t) -1);
     131           5 :                         if (r < 0) {
     132           0 :                                 log_error_errno(r, "Failed to wait: %m");
     133           0 :                                 goto fail;
     134             :                         }
     135             : 
     136           5 :                         continue;
     137             :                 }
     138             : 
     139          28 :                 if (!m)
     140           2 :                         continue;
     141             : 
     142          26 :                 sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
     143          26 :                 sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
     144          26 :                 log_info("Got message! member=%s pid="PID_FMT" label=%s",
     145             :                          strna(sd_bus_message_get_member(m)),
     146             :                          pid,
     147             :                          strna(label));
     148             :                 /* bus_message_dump(m); */
     149             :                 /* sd_bus_message_rewind(m, true); */
     150             : 
     151          26 :                 if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
     152             :                         const char *hello;
     153           1 :                         _cleanup_free_ char *lowercase = NULL;
     154             : 
     155           1 :                         r = sd_bus_message_read(m, "s", &hello);
     156           1 :                         if (r < 0) {
     157           0 :                                 log_error_errno(r, "Failed to get parameter: %m");
     158           0 :                                 goto fail;
     159             :                         }
     160             : 
     161           1 :                         lowercase = strdup(hello);
     162           1 :                         if (!lowercase) {
     163           0 :                                 r = log_oom();
     164           0 :                                 goto fail;
     165             :                         }
     166             : 
     167           1 :                         ascii_strlower(lowercase);
     168             : 
     169           1 :                         r = sd_bus_reply_method_return(m, "s", lowercase);
     170           1 :                         if (r < 0) {
     171           0 :                                 log_error_errno(r, "Failed to send reply: %m");
     172           0 :                                 goto fail;
     173             :                         }
     174          25 :                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
     175             : 
     176           1 :                         r = sd_bus_reply_method_return(m, NULL);
     177           1 :                         if (r < 0) {
     178           0 :                                 log_error_errno(r, "Failed to send reply: %m");
     179           0 :                                 goto fail;
     180             :                         }
     181             : 
     182           1 :                         client1_gone = true;
     183          24 :                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
     184             : 
     185           1 :                         r = sd_bus_reply_method_return(m, NULL);
     186           1 :                         if (r < 0) {
     187           0 :                                 log_error_errno(r, "Failed to send reply: %m");
     188           0 :                                 goto fail;
     189             :                         }
     190             : 
     191           1 :                         client2_gone = true;
     192          23 :                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
     193             : 
     194           2 :                         sleep(1);
     195             : 
     196           2 :                         r = sd_bus_reply_method_return(m, NULL);
     197           2 :                         if (r < 0) {
     198           0 :                                 log_error_errno(r, "Failed to send reply: %m");
     199           0 :                                 goto fail;
     200             :                         }
     201             : 
     202          21 :                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) {
     203             :                         int fd;
     204             :                         static const char x = 'X';
     205             : 
     206           1 :                         r = sd_bus_message_read(m, "h", &fd);
     207           1 :                         if (r < 0) {
     208           0 :                                 log_error_errno(r, "Failed to get parameter: %m");
     209           0 :                                 goto fail;
     210             :                         }
     211             : 
     212           1 :                         log_info("Received fd=%d", fd);
     213             : 
     214           1 :                         if (write(fd, &x, 1) < 0) {
     215           0 :                                 log_error_errno(errno, "Failed to write to fd: %m");
     216           0 :                                 safe_close(fd);
     217           0 :                                 goto fail;
     218             :                         }
     219             : 
     220           1 :                         r = sd_bus_reply_method_return(m, NULL);
     221           1 :                         if (r < 0) {
     222           0 :                                 log_error_errno(r, "Failed to send reply: %m");
     223           0 :                                 goto fail;
     224             :                         }
     225             : 
     226          20 :                 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
     227             : 
     228           0 :                         r = sd_bus_reply_method_error(
     229             :                                         m,
     230           0 :                                         &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
     231           0 :                         if (r < 0) {
     232           0 :                                 log_error_errno(r, "Failed to send reply: %m");
     233           0 :                                 goto fail;
     234             :                         }
     235             :                 }
     236             :         }
     237             : 
     238           1 :         r = 0;
     239             : 
     240           1 : fail:
     241           1 :         if (bus) {
     242           1 :                 sd_bus_flush(bus);
     243           1 :                 sd_bus_unref(bus);
     244             :         }
     245             : 
     246           1 :         return r;
     247             : }
     248             : 
     249           1 : static void* client1(void *p) {
     250           1 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     251           1 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     252           1 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     253             :         const char *hello;
     254             :         int r;
     255           2 :         _cleanup_close_pair_ int pp[2] = { -1, -1 };
     256             :         char x;
     257             : 
     258           1 :         r = sd_bus_open_user(&bus);
     259           1 :         if (r < 0) {
     260           0 :                 log_error_errno(r, "Failed to connect to user bus: %m");
     261           0 :                 goto finish;
     262             :         }
     263             : 
     264           1 :         r = sd_bus_call_method(
     265             :                         bus,
     266             :                         "org.freedesktop.systemd.test",
     267             :                         "/",
     268             :                         "org.freedesktop.systemd.test",
     269             :                         "LowerCase",
     270             :                         &error,
     271             :                         &reply,
     272             :                         "s",
     273             :                         "HELLO");
     274           1 :         if (r < 0) {
     275           0 :                 log_error_errno(r, "Failed to issue method call: %m");
     276           0 :                 goto finish;
     277             :         }
     278             : 
     279           1 :         r = sd_bus_message_read(reply, "s", &hello);
     280           1 :         if (r < 0) {
     281           0 :                 log_error_errno(r, "Failed to get string: %m");
     282           0 :                 goto finish;
     283             :         }
     284             : 
     285           1 :         assert_se(streq(hello, "hello"));
     286             : 
     287           1 :         if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
     288           0 :                 log_error_errno(errno, "Failed to allocate pipe: %m");
     289           0 :                 r = -errno;
     290           0 :                 goto finish;
     291             :         }
     292             : 
     293           1 :         log_info("Sending fd=%d", pp[1]);
     294             : 
     295           1 :         r = sd_bus_call_method(
     296             :                         bus,
     297             :                         "org.freedesktop.systemd.test",
     298             :                         "/",
     299             :                         "org.freedesktop.systemd.test",
     300             :                         "FileDescriptor",
     301             :                         &error,
     302             :                         NULL,
     303             :                         "h",
     304             :                         pp[1]);
     305           1 :         if (r < 0) {
     306           0 :                 log_error_errno(r, "Failed to issue method call: %m");
     307           0 :                 goto finish;
     308             :         }
     309             : 
     310           1 :         errno = 0;
     311           1 :         if (read(pp[0], &x, 1) <= 0) {
     312           0 :                 log_error("Failed to read from pipe: %s", errno != 0 ? strerror_safe(errno) : "early read");
     313           0 :                 goto finish;
     314             :         }
     315             : 
     316           1 :         r = 0;
     317             : 
     318           1 : finish:
     319           1 :         if (bus) {
     320           1 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *q;
     321             : 
     322           1 :                 r = sd_bus_message_new_method_call(
     323             :                                 bus,
     324             :                                 &q,
     325             :                                 "org.freedesktop.systemd.test",
     326             :                                 "/",
     327             :                                 "org.freedesktop.systemd.test",
     328             :                                 "ExitClient1");
     329           1 :                 if (r < 0)
     330           0 :                         log_error_errno(r, "Failed to allocate method call: %m");
     331             :                 else
     332           1 :                         sd_bus_send(bus, q, NULL);
     333             : 
     334             :         }
     335             : 
     336           1 :         return INT_TO_PTR(r);
     337             : }
     338             : 
     339           1 : static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
     340           1 :         bool *x = userdata;
     341             : 
     342           1 :         log_error_errno(sd_bus_message_get_errno(m), "Quit callback: %m");
     343             : 
     344           1 :         *x = 1;
     345           1 :         return 1;
     346             : }
     347             : 
     348           1 : static void* client2(void *p) {
     349           1 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
     350           1 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     351           2 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     352           1 :         bool quit = false;
     353             :         const char *mid;
     354             :         int r;
     355             : 
     356           1 :         r = sd_bus_open_user(&bus);
     357           1 :         if (r < 0) {
     358           0 :                 log_error_errno(r, "Failed to connect to user bus: %m");
     359           0 :                 goto finish;
     360             :         }
     361             : 
     362           1 :         r = sd_bus_message_new_method_call(
     363             :                         bus,
     364             :                         &m,
     365             :                         "org.freedesktop.systemd.test",
     366             :                         "/foo/bar/waldo/piep",
     367             :                         "org.object.test",
     368             :                         "Foobar");
     369           1 :         if (r < 0) {
     370           0 :                 log_error_errno(r, "Failed to allocate method call: %m");
     371           0 :                 goto finish;
     372             :         }
     373             : 
     374           1 :         r = sd_bus_send(bus, m, NULL);
     375           1 :         if (r < 0) {
     376           0 :                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
     377           0 :                 goto finish;
     378             :         }
     379             : 
     380           1 :         m = sd_bus_message_unref(m);
     381             : 
     382           1 :         r = sd_bus_message_new_signal(
     383             :                         bus,
     384             :                         &m,
     385             :                         "/foobar",
     386             :                         "foo.bar",
     387             :                         "Notify");
     388           1 :         if (r < 0) {
     389           0 :                 log_error_errno(r, "Failed to allocate signal: %m");
     390           0 :                 goto finish;
     391             :         }
     392             : 
     393           1 :         r = sd_bus_send(bus, m, NULL);
     394           1 :         if (r < 0) {
     395           0 :                 log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
     396           0 :                 goto finish;
     397             :         }
     398             : 
     399           1 :         m = sd_bus_message_unref(m);
     400             : 
     401           1 :         r = sd_bus_message_new_method_call(
     402             :                         bus,
     403             :                         &m,
     404             :                         "org.freedesktop.systemd.test",
     405             :                         "/",
     406             :                         "org.freedesktop.DBus.Peer",
     407             :                         "GetMachineId");
     408           1 :         if (r < 0) {
     409           0 :                 log_error_errno(r, "Failed to allocate method call: %m");
     410           0 :                 goto finish;
     411             :         }
     412             : 
     413           1 :         r = sd_bus_call(bus, m, 0, &error, &reply);
     414           1 :         if (r < 0) {
     415           0 :                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
     416           0 :                 goto finish;
     417             :         }
     418             : 
     419           1 :         r = sd_bus_message_read(reply, "s", &mid);
     420           1 :         if (r < 0) {
     421           0 :                 log_error_errno(r, "Failed to parse machine ID: %m");
     422           0 :                 goto finish;
     423             :         }
     424             : 
     425           1 :         log_info("Machine ID is %s.", mid);
     426             : 
     427           1 :         m = sd_bus_message_unref(m);
     428             : 
     429           1 :         r = sd_bus_message_new_method_call(
     430             :                         bus,
     431             :                         &m,
     432             :                         "org.freedesktop.systemd.test",
     433             :                         "/",
     434             :                         "org.freedesktop.systemd.test",
     435             :                         "Slow");
     436           1 :         if (r < 0) {
     437           0 :                 log_error_errno(r, "Failed to allocate method call: %m");
     438           0 :                 goto finish;
     439             :         }
     440             : 
     441           1 :         reply = sd_bus_message_unref(reply);
     442             : 
     443           1 :         r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
     444           1 :         if (r < 0)
     445           1 :                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
     446             :         else
     447           0 :                 log_info("Slow call succeed.");
     448             : 
     449           1 :         m = sd_bus_message_unref(m);
     450             : 
     451           1 :         r = sd_bus_message_new_method_call(
     452             :                         bus,
     453             :                         &m,
     454             :                         "org.freedesktop.systemd.test",
     455             :                         "/",
     456             :                         "org.freedesktop.systemd.test",
     457             :                         "Slow");
     458           1 :         if (r < 0) {
     459           0 :                 log_error_errno(r, "Failed to allocate method call: %m");
     460           0 :                 goto finish;
     461             :         }
     462             : 
     463           1 :         r = sd_bus_call_async(bus, NULL, m, quit_callback, &quit, 200 * USEC_PER_MSEC);
     464           1 :         if (r < 0) {
     465           0 :                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
     466           0 :                 goto finish;
     467             :         }
     468             : 
     469           4 :         while (!quit) {
     470           3 :                 r = sd_bus_process(bus, NULL);
     471           3 :                 if (r < 0) {
     472           0 :                         log_error_errno(r, "Failed to process requests: %m");
     473           0 :                         goto finish;
     474             :                 }
     475           3 :                 if (r == 0) {
     476           1 :                         r = sd_bus_wait(bus, (uint64_t) -1);
     477           1 :                         if (r < 0) {
     478           0 :                                 log_error_errno(r, "Failed to wait: %m");
     479           0 :                                 goto finish;
     480             :                         }
     481             :                 }
     482             :         }
     483             : 
     484           1 :         r = 0;
     485             : 
     486           1 : finish:
     487           1 :         if (bus) {
     488           1 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *q;
     489             : 
     490           1 :                 r = sd_bus_message_new_method_call(
     491             :                                 bus,
     492             :                                 &q,
     493             :                                 "org.freedesktop.systemd.test",
     494             :                                 "/",
     495             :                                 "org.freedesktop.systemd.test",
     496             :                                 "ExitClient2");
     497           1 :                 if (r < 0) {
     498           0 :                         log_error_errno(r, "Failed to allocate method call: %m");
     499           0 :                         goto finish;
     500             :                 }
     501             : 
     502           1 :                 (void) sd_bus_send(bus, q, NULL);
     503             :         }
     504             : 
     505           1 :         return INT_TO_PTR(r);
     506             : }
     507             : 
     508           1 : int main(int argc, char *argv[]) {
     509             :         pthread_t c1, c2;
     510             :         sd_bus *bus;
     511             :         void *p;
     512             :         int q, r;
     513             : 
     514           1 :         test_setup_logging(LOG_INFO);
     515             : 
     516           1 :         r = server_init(&bus);
     517           1 :         if (r < 0)
     518           0 :                 return log_tests_skipped("Failed to connect to bus");
     519             : 
     520           1 :         log_info("Initialized...");
     521             : 
     522           1 :         r = pthread_create(&c1, NULL, client1, bus);
     523           1 :         if (r != 0)
     524           0 :                 return EXIT_FAILURE;
     525             : 
     526           1 :         r = pthread_create(&c2, NULL, client2, bus);
     527           1 :         if (r != 0)
     528           0 :                 return EXIT_FAILURE;
     529             : 
     530           1 :         r = server(bus);
     531             : 
     532           1 :         q = pthread_join(c1, &p);
     533           1 :         if (q != 0)
     534           0 :                 return EXIT_FAILURE;
     535           1 :         if (PTR_TO_INT(p) < 0)
     536           0 :                 return EXIT_FAILURE;
     537             : 
     538           1 :         q = pthread_join(c2, &p);
     539           1 :         if (q != 0)
     540           0 :                 return EXIT_FAILURE;
     541           1 :         if (PTR_TO_INT(p) < 0)
     542           0 :                 return EXIT_FAILURE;
     543             : 
     544           1 :         if (r < 0)
     545           0 :                 return EXIT_FAILURE;
     546             : 
     547           1 :         return EXIT_SUCCESS;
     548             : }

Generated by: LCOV version 1.14