chiark / gitweb /
sd-bus: add APIs to request/release names asynchronously
authorLennart Poettering <lennart@poettering.net>
Mon, 18 Dec 2017 19:10:13 +0000 (20:10 +0100)
committerSven Eden <yamakuzure@gmx.net>
Wed, 30 May 2018 05:49:57 +0000 (07:49 +0200)
They do the same thing as their synchronous counterparts, but only
enqueue the operation, thus removing synchronization points during
service initialization.

If the callback function is passed as NULL we'll fallback to generic
implementations of the reply handlers, that terminate the connection if
the requested name cannot be acquired, under the assumption that not
being able to acquire the name is a technical problem.

src/libelogind/libelogind.sym
src/libelogind/sd-bus/bus-control.c
src/libelogind/sd-bus/bus-internal.h
src/libelogind/sd-bus/sd-bus.c
src/systemd/sd-bus.h

index 5aa25369776b66987438d4e9d2b8419a0d578031..ac6645051c91424dca723aa9e6b08215ebb37be0 100644 (file)
@@ -541,4 +541,6 @@ LIBSYSTEMD_237 {
 global:
         sd_bus_set_watch_bind;
         sd_bus_get_watch_bind;
+        sd_bus_request_name_async;
+        sd_bus_release_name_async;
 } LIBSYSTEMD_236;
index e1e75da6797a352d47c1255d168978a9caa7d4ed..403800131844f5f12e065f4b4fdf79a912a98af3 100644 (file)
@@ -57,14 +57,18 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
         return 0;
 }
 
-_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        uint32_t ret, param = 0;
-        int r;
+static int validate_request_name_parameters(
+                sd_bus *bus,
+                const char *name,
+                uint64_t flags,
+                uint32_t *ret_param) {
+
+        uint32_t param = 0;
+
+        assert(bus);
+        assert(name);
+        assert(ret_param);
 
-        assert_return(bus, -EINVAL);
-        assert_return(name, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
         assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
         assert_return(service_name_is_valid(name), -EINVAL);
         assert_return(name[0] != ':', -EINVAL);
@@ -86,6 +90,28 @@ _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
         if (!(flags & SD_BUS_NAME_QUEUE))
                 param |= BUS_NAME_DO_NOT_QUEUE;
 
+        *ret_param = param;
+
+        return 0;
+}
+
+_public_ int sd_bus_request_name(
+                sd_bus *bus,
+                const char *name,
+                uint64_t flags) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        uint32_t ret, param = 0;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = validate_request_name_parameters(bus, name, flags, &param);
+        if (r < 0)
+                return r;
+
         r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.DBus",
@@ -104,26 +130,112 @@ _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
         if (r < 0)
                 return r;
 
-        if (ret == BUS_NAME_ALREADY_OWNER)
+        switch (ret) {
+
+        case BUS_NAME_ALREADY_OWNER:
                 return -EALREADY;
-        else if (ret == BUS_NAME_EXISTS)
+
+        case BUS_NAME_EXISTS:
                 return -EEXIST;
-        else if (ret == BUS_NAME_IN_QUEUE)
+
+        case BUS_NAME_IN_QUEUE:
                 return 0;
-        else if (ret == BUS_NAME_PRIMARY_OWNER)
+
+        case BUS_NAME_PRIMARY_OWNER:
                 return 1;
+        }
 
         return -EIO;
 }
 
-_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+static int default_request_name_handler(
+                sd_bus_message *m,
+                void *userdata,
+                sd_bus_error *ret_error) {
+
         uint32_t ret;
         int r;
 
+        assert(m);
+
+        if (sd_bus_message_is_method_error(m, NULL)) {
+                log_debug_errno(sd_bus_message_get_errno(m),
+                                "Unable to request name, failing connection: %s",
+                                sd_bus_message_get_error(m)->message);
+
+                bus_enter_closing(sd_bus_message_get_bus(m));
+                return 1;
+        }
+
+        r = sd_bus_message_read(m, "u", &ret);
+        if (r < 0)
+                return r;
+
+        switch (ret) {
+
+        case BUS_NAME_ALREADY_OWNER:
+                log_debug("Already owner of requested service name, ignoring.");
+                return 1;
+
+        case BUS_NAME_IN_QUEUE:
+                log_debug("In queue for requested service name.");
+                return 1;
+
+        case BUS_NAME_PRIMARY_OWNER:
+                log_debug("Successfully acquired requested service name.");
+                return 1;
+
+        case BUS_NAME_EXISTS:
+                log_debug("Requested service name already owned, failing connection.");
+                bus_enter_closing(sd_bus_message_get_bus(m));
+                return 1;
+        }
+
+        log_debug("Unexpected response from RequestName(), failing connection.");
+        bus_enter_closing(sd_bus_message_get_bus(m));
+        return 1;
+}
+
+_public_ int sd_bus_request_name_async(
+                sd_bus *bus,
+                sd_bus_slot **ret_slot,
+                const char *name,
+                uint64_t flags,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
+
+        uint32_t param = 0;
+        int r;
+
         assert_return(bus, -EINVAL);
         assert_return(name, -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = validate_request_name_parameters(bus, name, flags, &param);
+        if (r < 0)
+                return r;
+
+        return sd_bus_call_method_async(
+                        bus,
+                        ret_slot,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "RequestName",
+                        callback ?: default_request_name_handler,
+                        userdata,
+                        "su",
+                        name,
+                        param);
+}
+
+static int validate_release_name_parameters(
+                sd_bus *bus,
+                const char *name) {
+
+        assert(bus);
+        assert(name);
+
         assert_return(service_name_is_valid(name), -EINVAL);
         assert_return(name[0] != ':', -EINVAL);
 
@@ -137,6 +249,25 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
         if (!BUS_IS_OPEN(bus->state))
                 return -ENOTCONN;
 
+        return 0;
+}
+
+_public_ int sd_bus_release_name(
+                sd_bus *bus,
+                const char *name) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        uint32_t ret;
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = validate_release_name_parameters(bus, name);
+        if (r < 0)
+                return r;
+
         r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.DBus",
@@ -153,14 +284,93 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
         r = sd_bus_message_read(reply, "u", &ret);
         if (r < 0)
                 return r;
-        if (ret == BUS_NAME_NON_EXISTENT)
+
+        switch (ret) {
+
+        case BUS_NAME_NON_EXISTENT:
                 return -ESRCH;
-        if (ret == BUS_NAME_NOT_OWNER)
+
+        case BUS_NAME_NOT_OWNER:
                 return -EADDRINUSE;
-        if (ret == BUS_NAME_RELEASED)
+
+        case BUS_NAME_RELEASED:
                 return 0;
+        }
+
+        return -EIO;
+}
+
+static int default_release_name_handler(
+                sd_bus_message *m,
+                void *userdata,
+                sd_bus_error *ret_error) {
+
+        uint32_t ret;
+        int r;
+
+        assert(m);
 
-        return -EINVAL;
+        if (sd_bus_message_is_method_error(m, NULL)) {
+                log_debug_errno(sd_bus_message_get_errno(m),
+                                "Unable to release name, failing connection: %s",
+                                sd_bus_message_get_error(m)->message);
+
+                bus_enter_closing(sd_bus_message_get_bus(m));
+                return 1;
+        }
+
+        r = sd_bus_message_read(m, "u", &ret);
+        if (r < 0)
+                return r;
+
+        switch (ret) {
+
+        case BUS_NAME_NON_EXISTENT:
+                log_debug("Name asked to release is not taken currently, ignoring.");
+                return 1;
+
+        case BUS_NAME_NOT_OWNER:
+                log_debug("Name asked to release is owned by somebody else, ignoring.");
+                return 1;
+
+        case BUS_NAME_RELEASED:
+                log_debug("Name successfully released.");
+                return 1;
+        }
+
+        log_debug("Unexpected response from ReleaseName(), failing connection.");
+        bus_enter_closing(sd_bus_message_get_bus(m));
+        return 1;
+}
+
+_public_ int sd_bus_release_name_async(
+                sd_bus *bus,
+                sd_bus_slot **ret_slot,
+                const char *name,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
+
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(name, -EINVAL);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        r = validate_release_name_parameters(bus, name);
+        if (r < 0)
+                return r;
+
+        return sd_bus_call_method_async(
+                        bus,
+                        ret_slot,
+                        "org.freedesktop.DBus",
+                        "/org/freedesktop/DBus",
+                        "org.freedesktop.DBus",
+                        "ReleaseName",
+                        callback ?: default_release_name_handler,
+                        userdata,
+                        "s",
+                        name);
 }
 
 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
index ce4090c431dd71b5f6acbeef106e12ca4e9ae75b..b0c519cf9246567583a53919dc2eac9e54b5b134 100644 (file)
@@ -413,3 +413,5 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
                 if (!assert_log(expr, #expr))                           \
                         return sd_bus_error_set_errno(error, r);        \
         } while (false)
+
+void bus_enter_closing(sd_bus *bus);
index 98a25937285e8c00768f04658cdccbd9b5c47d4d..01c4ca012b458bd0f51659eefc07fd04ff162e6b 100644 (file)
@@ -1369,7 +1369,7 @@ _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
         return sd_bus_unref(bus);
 }
 
-static void bus_enter_closing(sd_bus *bus) {
+void bus_enter_closing(sd_bus *bus) {
         assert(bus);
 
         if (!IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING, BUS_HELLO, BUS_RUNNING))
index 62f10b632244b10f340605a468b351371418a853..f212bfb8ca978c24d0cf46e3bb99783ec7153840 100644 (file)
@@ -302,7 +302,9 @@ int sd_bus_message_rewind(sd_bus_message *m, int complete);
 
 int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
 int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags);
+int sd_bus_request_name_async(sd_bus *bus, sd_bus_slot **ret_slot, const char *name, uint64_t flags, sd_bus_message_handler_t callback, void *userdata);
 int sd_bus_release_name(sd_bus *bus, const char *name);
+int sd_bus_release_name_async(sd_bus *bus, sd_bus_slot **ret_slot, const char *name, sd_bus_message_handler_t callback, void *userdata);
 int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable); /* free the results */
 int sd_bus_get_name_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds); /* unref the result! */
 int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine);