diff --git a/man/sd-bus.xml b/man/sd-bus.xml
index f43af89789..36925ba8c4 100644
--- a/man/sd-bus.xml
+++ b/man/sd-bus.xml
@@ -68,6 +68,8 @@
sd_bus_emit_properties_changed_strv3,
sd_bus_emit_signal3,
sd_bus_emit_signalv3,
+sd_bus_emit_signal_to3,
+sd_bus_emit_signal_tov3,
sd-bus-errors3,
sd_bus_error3,
sd_bus_error_add_map3,
@@ -122,6 +124,7 @@
sd_bus_message_new_method_call3,
sd_bus_message_new_method_error3,
sd_bus_message_new_signal3,
+sd_bus_message_new_signal_to3,
sd_bus_message_open_container3,
sd_bus_message_peek_type3,
sd_bus_message_read3,
diff --git a/man/sd_bus_emit_signal.xml b/man/sd_bus_emit_signal.xml
index 08d5be400e..52d08b7a92 100644
--- a/man/sd_bus_emit_signal.xml
+++ b/man/sd_bus_emit_signal.xml
@@ -19,6 +19,8 @@
sd_bus_emit_signal
sd_bus_emit_signalv
+ sd_bus_emit_signal_to
+ sd_bus_emit_signal_tov
sd_bus_emit_interfaces_added
sd_bus_emit_interfaces_added_strv
sd_bus_emit_interfaces_removed
@@ -55,6 +57,28 @@
va_list ap
+
+ int sd_bus_emit_signal_to
+ sd_bus *bus
+ const char *destination
+ const char *path
+ const char *interface
+ const char *member
+ const char *types
+ ...
+
+
+
+ int sd_bus_emit_signal_tov
+ sd_bus *bus
+ const char *destination
+ const char *path
+ const char *interface
+ const char *member
+ const char *types
+ va_list ap
+
+
int sd_bus_emit_interfaces_added
sd_bus *bus
@@ -128,6 +152,11 @@
equivalent to sd_bus_message_append(), except that it is called with a
va_list instead of a variable number of arguments.
+ sd_bus_emit_signal_to() and sd_bus_emit_signal_tov() are
+ identical to sd_bus_emit_signal() and sd_bus_emit_signalv(), except
+ that they can emit the signal to a single destination. Give destination as
+ NULL to broadcast the signal.
+
sd_bus_emit_interfaces_added() and
sd_bus_emit_interfaces_removed() are used to implement the
InterfacesAdded and InterfacesRemoved signals of the
diff --git a/man/sd_bus_message_new_signal.xml b/man/sd_bus_message_new_signal.xml
index 17862deb0b..0c4f6e3a35 100644
--- a/man/sd_bus_message_new_signal.xml
+++ b/man/sd_bus_message_new_signal.xml
@@ -18,6 +18,7 @@
sd_bus_message_new_signal
+ sd_bus_message_new_signal_to
Create a signal message
@@ -34,6 +35,16 @@
const char *interface
const char *member
+
+
+ int sd_bus_message_new_signal_to
+ sd_bus *bus
+ sd_bus_message **m
+ const char *destination
+ const char *path
+ const char *interface
+ const char *member
+
@@ -49,6 +60,10 @@
for a short description of the meaning of the path,
interface, and member parameters.
+
+ sd_bus_message_new_signal_to() is a shorthand for creating a new bus message
+ to a specific destination. It's behavior is similar to calling sd_bus_message_new_signal()
+ followed by calling sd_bus_message_set_destination()3.
@@ -115,6 +130,7 @@
systemd1,
sd-bus3,
sd_bus_emit_signal3
+ sd_bus_message_set_destination3
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 3b72320f0c..07acb99271 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -796,3 +796,10 @@ global:
sd_hwdb_new_from_path;
} LIBSYSTEMD_251;
+
+LIBSYSTEMD_253 {
+global:
+ sd_bus_emit_signal_to;
+ sd_bus_emit_signal_tov;
+ sd_bus_message_new_signal_to;
+} LIBSYSTEMD_252;
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 6a3f2ea0ec..6974e210a2 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -17,8 +17,9 @@ _public_ int sd_bus_message_send(sd_bus_message *reply) {
return sd_bus_send(reply->bus, reply, NULL);
}
-_public_ int sd_bus_emit_signalv(
+_public_ int sd_bus_emit_signal_tov(
sd_bus *bus,
+ const char *destination,
const char *path,
const char *interface,
const char *member,
@@ -34,7 +35,7 @@ _public_ int sd_bus_emit_signalv(
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- r = sd_bus_message_new_signal(bus, &m, path, interface, member);
+ r = sd_bus_message_new_signal_to(bus, &m, destination, path, interface, member);
if (r < 0)
return r;
@@ -47,6 +48,34 @@ _public_ int sd_bus_emit_signalv(
return sd_bus_send(bus, m, NULL);
}
+_public_ int sd_bus_emit_signal_to(
+ sd_bus *bus,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *types, ...) {
+
+ va_list ap;
+ int r;
+
+ va_start(ap, types);
+ r = sd_bus_emit_signal_tov(bus, destination, path, interface, member, types, ap);
+ va_end(ap);
+
+ return r;
+}
+
+_public_ int sd_bus_emit_signalv(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *types, va_list ap) {
+
+ return sd_bus_emit_signal_tov(bus, NULL, path, interface, member, types, ap);
+}
+
_public_ int sd_bus_emit_signal(
sd_bus *bus,
const char *path,
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index d9c52d64c0..39e21480ac 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -483,9 +483,10 @@ _public_ int sd_bus_message_new(
return 0;
}
-_public_ int sd_bus_message_new_signal(
+_public_ int sd_bus_message_new_signal_to(
sd_bus *bus,
sd_bus_message **m,
+ const char *destination,
const char *path,
const char *interface,
const char *member) {
@@ -496,6 +497,7 @@ _public_ int sd_bus_message_new_signal(
assert_return(bus, -ENOTCONN);
assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(bus->state != BUS_UNSET, -ENOTCONN);
+ assert_return(!destination || service_name_is_valid(destination), -EINVAL);
assert_return(object_path_is_valid(path), -EINVAL);
assert_return(interface_name_is_valid(interface), -EINVAL);
assert_return(member_name_is_valid(member), -EINVAL);
@@ -519,10 +521,26 @@ _public_ int sd_bus_message_new_signal(
if (r < 0)
return r;
+ if (destination) {
+ r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
+ if (r < 0)
+ return r;
+ }
+
*m = TAKE_PTR(t);
return 0;
}
+_public_ int sd_bus_message_new_signal(
+ sd_bus *bus,
+ sd_bus_message **m,
+ const char *path,
+ const char *interface,
+ const char *member) {
+
+ return sd_bus_message_new_signal_to(bus, m, NULL, path, interface, member);
+}
+
_public_ int sd_bus_message_new_method_call(
sd_bus *bus,
sd_bus_message **m,
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index 93e8ebfb1b..09401a9784 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -21,7 +21,10 @@
#include "util.h"
static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
+ log_info("Match triggered! destination=%s interface=%s member=%s",
+ strna(sd_bus_message_get_destination(m)),
+ strna(sd_bus_message_get_interface(m)),
+ strna(sd_bus_message_get_member(m)));
return 0;
}
@@ -95,6 +98,12 @@ static int server_init(sd_bus **_bus) {
goto fail;
}
+ r = sd_bus_match_signal(bus, NULL, NULL, NULL, "foo.bar", "NotifyTo", match_callback, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Failed to request match: %m");
+ goto fail;
+ }
+
r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
if (r < 0) {
log_error_errno(r, "Failed to add match: %m");
@@ -397,6 +406,26 @@ static void* client2(void *p) {
m = sd_bus_message_unref(m);
+ r = sd_bus_message_new_signal_to(
+ bus,
+ &m,
+ "org.freedesktop.systemd.test",
+ "/foobar",
+ "foo.bar",
+ "NotifyTo");
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate signal to: %m");
+ goto finish;
+ }
+
+ r = sd_bus_send(bus, m, NULL);
+ if (r < 0) {
+ log_error("Failed to issue signal to: %s", bus_error_message(&error, r));
+ goto finish;
+ }
+
+ m = sd_bus_message_unref(m);
+
r = sd_bus_message_new_method_call(
bus,
&m,
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 74bc56b427..bd3da36c36 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -260,6 +260,7 @@ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot);
int sd_bus_message_new(sd_bus *bus, sd_bus_message **m, uint8_t type);
int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member);
+int sd_bus_message_new_signal_to(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member);
int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member);
int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m);
int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e);
@@ -379,6 +380,8 @@ int sd_bus_reply_method_errnof(sd_bus_message *call, int error, const char *form
int sd_bus_emit_signalv(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, va_list ap);
int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, ...);
+int sd_bus_emit_signal_tov(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, const char *types, va_list ap);
+int sd_bus_emit_signal_to(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, const char *types, ...);
int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names);
int sd_bus_emit_properties_changed(sd_bus *bus, const char *path, const char *interface, const char *name, ...) _sd_sentinel_;