LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - test-bus-watch-bind.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 118 118 100.0 %
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 <pthread.h>
       4             : 
       5             : #include "sd-bus.h"
       6             : #include "sd-event.h"
       7             : #include "sd-id128.h"
       8             : 
       9             : #include "alloc-util.h"
      10             : #include "fd-util.h"
      11             : #include "fs-util.h"
      12             : #include "mkdir.h"
      13             : #include "path-util.h"
      14             : #include "random-util.h"
      15             : #include "rm-rf.h"
      16             : #include "socket-util.h"
      17             : #include "string-util.h"
      18             : #include "tmpfile-util.h"
      19             : #include "tests.h"
      20             : 
      21           2 : static int method_foobar(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
      22           2 :         log_info("Got Foobar() call.");
      23             : 
      24           2 :         assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0) >= 0);
      25           2 :         return sd_bus_reply_method_return(m, NULL);
      26             : }
      27             : 
      28           1 : static int method_exit(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
      29           1 :         log_info("Got Exit() call");
      30           1 :         assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 1) >= 0);
      31           1 :         return sd_bus_reply_method_return(m, NULL);
      32             : }
      33             : 
      34             : static const sd_bus_vtable vtable[] = {
      35             :         SD_BUS_VTABLE_START(0),
      36             :         SD_BUS_METHOD("Foobar", NULL, NULL, method_foobar, SD_BUS_VTABLE_UNPRIVILEGED),
      37             :         SD_BUS_METHOD("Exit", NULL, NULL, method_exit, SD_BUS_VTABLE_UNPRIVILEGED),
      38             :         SD_BUS_VTABLE_END,
      39             : };
      40             : 
      41           1 : static void* thread_server(void *p) {
      42           1 :         _cleanup_free_ char *suffixed = NULL, *suffixed2 = NULL, *d = NULL;
      43           2 :         _cleanup_close_ int fd = -1;
      44           1 :         union sockaddr_union u = {};
      45           1 :         const char *path = p;
      46             :         int salen;
      47             : 
      48           1 :         log_debug("Initializing server");
      49             : 
      50             :         /* Let's play some games, by slowly creating the socket directory, and renaming it in the middle */
      51           1 :         (void) usleep(100 * USEC_PER_MSEC);
      52             : 
      53           1 :         assert_se(mkdir_parents(path, 0755) >= 0);
      54           1 :         (void) usleep(100 * USEC_PER_MSEC);
      55             : 
      56           1 :         d = dirname_malloc(path);
      57           1 :         assert_se(d);
      58           1 :         assert_se(asprintf(&suffixed, "%s.%" PRIx64, d, random_u64()) >= 0);
      59           1 :         assert_se(rename(d, suffixed) >= 0);
      60           1 :         (void) usleep(100 * USEC_PER_MSEC);
      61             : 
      62           1 :         assert_se(asprintf(&suffixed2, "%s.%" PRIx64, d, random_u64()) >= 0);
      63           1 :         assert_se(symlink(suffixed2, d) >= 0);
      64           1 :         (void) usleep(100 * USEC_PER_MSEC);
      65             : 
      66           1 :         assert_se(symlink(basename(suffixed), suffixed2) >= 0);
      67           1 :         (void) usleep(100 * USEC_PER_MSEC);
      68             : 
      69           1 :         salen = sockaddr_un_set_path(&u.un, path);
      70           1 :         assert_se(salen >= 0);
      71             : 
      72           1 :         fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
      73           1 :         assert_se(fd >= 0);
      74             : 
      75           1 :         assert_se(bind(fd, &u.sa, salen) >= 0);
      76           1 :         usleep(100 * USEC_PER_MSEC);
      77             : 
      78           1 :         assert_se(listen(fd, SOMAXCONN) >= 0);
      79           1 :         usleep(100 * USEC_PER_MSEC);
      80             : 
      81           1 :         assert_se(touch(path) >= 0);
      82           1 :         usleep(100 * USEC_PER_MSEC);
      83             : 
      84           1 :         log_debug("Initialized server");
      85             : 
      86           2 :         for (;;) {
      87           3 :                 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
      88           3 :                 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
      89             :                 sd_id128_t id;
      90             :                 int bus_fd, code;
      91             : 
      92           3 :                 assert_se(sd_id128_randomize(&id) >= 0);
      93             : 
      94           3 :                 assert_se(sd_event_new(&event) >= 0);
      95             : 
      96           3 :                 bus_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
      97           3 :                 assert_se(bus_fd >= 0);
      98             : 
      99           3 :                 log_debug("Accepted server connection");
     100             : 
     101           3 :                 assert_se(sd_bus_new(&bus) >= 0);
     102           3 :                 assert_se(sd_bus_set_description(bus, "server") >= 0);
     103           3 :                 assert_se(sd_bus_set_fd(bus, bus_fd, bus_fd) >= 0);
     104           3 :                 assert_se(sd_bus_set_server(bus, true, id) >= 0);
     105             :                 /* assert_se(sd_bus_set_anonymous(bus, true) >= 0); */
     106             : 
     107           3 :                 assert_se(sd_bus_attach_event(bus, event, 0) >= 0);
     108             : 
     109           3 :                 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "foo.TestInterface", vtable, NULL) >= 0);
     110             : 
     111           3 :                 assert_se(sd_bus_start(bus) >= 0);
     112             : 
     113           3 :                 assert_se(sd_event_loop(event) >= 0);
     114             : 
     115           3 :                 assert_se(sd_event_get_exit_code(event, &code) >= 0);
     116             : 
     117           3 :                 if (code > 0)
     118           1 :                         break;
     119             :         }
     120             : 
     121           1 :         log_debug("Server done");
     122             : 
     123           1 :         return NULL;
     124             : }
     125             : 
     126           1 : static void* thread_client1(void *p) {
     127           1 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     128           2 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     129           1 :         const char *path = p, *t;
     130             :         int r;
     131             : 
     132           1 :         log_debug("Initializing client1");
     133             : 
     134           1 :         assert_se(sd_bus_new(&bus) >= 0);
     135           1 :         assert_se(sd_bus_set_description(bus, "client1") >= 0);
     136             : 
     137           5 :         t = strjoina("unix:path=", path);
     138           1 :         assert_se(sd_bus_set_address(bus, t) >= 0);
     139           1 :         assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
     140           1 :         assert_se(sd_bus_start(bus) >= 0);
     141             : 
     142           1 :         r = sd_bus_call_method(bus, "foo.bar", "/foo", "foo.TestInterface", "Foobar", &error, NULL, NULL);
     143           1 :         assert_se(r >= 0);
     144             : 
     145           1 :         log_debug("Client1 done");
     146             : 
     147           1 :         return NULL;
     148             : }
     149             : 
     150           1 : static int client2_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
     151           1 :         assert_se(sd_bus_message_is_method_error(m, NULL) == 0);
     152           1 :         assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0) >= 0);
     153           1 :         return 0;
     154             : }
     155             : 
     156           1 : static void* thread_client2(void *p) {
     157           1 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     158           2 :         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
     159           1 :         const char *path = p, *t;
     160             : 
     161           1 :         log_debug("Initializing client2");
     162             : 
     163           1 :         assert_se(sd_event_new(&event) >= 0);
     164           1 :         assert_se(sd_bus_new(&bus) >= 0);
     165           1 :         assert_se(sd_bus_set_description(bus, "client2") >= 0);
     166             : 
     167           5 :         t = strjoina("unix:path=", path);
     168           1 :         assert_se(sd_bus_set_address(bus, t) >= 0);
     169           1 :         assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
     170           1 :         assert_se(sd_bus_attach_event(bus, event, 0) >= 0);
     171           1 :         assert_se(sd_bus_start(bus) >= 0);
     172             : 
     173           1 :         assert_se(sd_bus_call_method_async(bus, NULL, "foo.bar", "/foo", "foo.TestInterface", "Foobar", client2_callback, NULL, NULL) >= 0);
     174             : 
     175           1 :         assert_se(sd_event_loop(event) >= 0);
     176             : 
     177           1 :         log_debug("Client2 done");
     178             : 
     179           1 :         return NULL;
     180             : }
     181             : 
     182           1 : static void request_exit(const char *path) {
     183           1 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     184             :         const char *t;
     185             : 
     186           1 :         assert_se(sd_bus_new(&bus) >= 0);
     187             : 
     188           5 :         t = strjoina("unix:path=", path);
     189           1 :         assert_se(sd_bus_set_address(bus, t) >= 0);
     190           1 :         assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
     191           1 :         assert_se(sd_bus_set_description(bus, "request-exit") >= 0);
     192           1 :         assert_se(sd_bus_start(bus) >= 0);
     193             : 
     194           1 :         assert_se(sd_bus_call_method(bus, "foo.bar", "/foo", "foo.TestInterface", "Exit", NULL, NULL, NULL) >= 0);
     195           1 : }
     196             : 
     197           1 : int main(int argc, char *argv[]) {
     198           2 :         _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
     199             :         pthread_t server, client1, client2;
     200             :         char *path;
     201             : 
     202           1 :         test_setup_logging(LOG_DEBUG);
     203             : 
     204             :         /* We use /dev/shm here rather than /tmp, since some weird distros might set up /tmp as some weird fs that
     205             :          * doesn't support inotify properly. */
     206           1 :         assert_se(mkdtemp_malloc("/dev/shm/systemd-watch-bind-XXXXXX", &d) >= 0);
     207             : 
     208           5 :         path = strjoina(d, "/this/is/a/socket");
     209             : 
     210           1 :         assert_se(pthread_create(&server, NULL, thread_server, path) == 0);
     211           1 :         assert_se(pthread_create(&client1, NULL, thread_client1, path) == 0);
     212           1 :         assert_se(pthread_create(&client2, NULL, thread_client2, path) == 0);
     213             : 
     214           1 :         assert_se(pthread_join(client1, NULL) == 0);
     215           1 :         assert_se(pthread_join(client2, NULL) == 0);
     216             : 
     217           1 :         request_exit(path);
     218             : 
     219           1 :         assert_se(pthread_join(server, NULL) == 0);
     220             : 
     221           1 :         return 0;
     222             : }

Generated by: LCOV version 1.14