1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "bus-internal.h"
26 #include "bus-track.h"
31 sd_bus_track_handler_t handler;
34 LIST_FIELDS(sd_bus_track, queue);
40 #define MATCH_PREFIX \
42 "sender='org.freedesktop.DBus'," \
43 "path='/org/freedesktop/DBus'," \
44 "interface='org.freedesktop.DBus'," \
45 "member='NameOwnerChanged'," \
48 #define MATCH_SUFFIX \
51 #define MATCH_FOR_NAME(name) \
54 size_t _l = strlen(name); \
55 _x = alloca(strlen(MATCH_PREFIX)+_l+strlen(MATCH_SUFFIX)+1); \
56 strcpy(stpcpy(stpcpy(_x, MATCH_PREFIX), name), MATCH_SUFFIX); \
60 static void bus_track_add_to_queue(sd_bus_track *track) {
69 LIST_PREPEND(queue, track->bus->track_queue, track);
70 track->in_queue = true;
73 static void bus_track_remove_from_queue(sd_bus_track *track) {
79 LIST_REMOVE(queue, track->bus->track_queue, track);
80 track->in_queue = false;
83 _public_ int sd_bus_track_new(
86 sd_bus_track_handler_t handler,
91 assert_return(bus, -EINVAL);
92 assert_return(track, -EINVAL);
94 t = new0(sd_bus_track, 1);
100 t->userdata = userdata;
101 t->bus = sd_bus_ref(bus);
103 bus_track_add_to_queue(t);
109 _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) {
110 assert_return(track, NULL);
112 assert(track->n_ref > 0);
119 _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
125 assert(track->n_ref > 0);
127 if (track->n_ref > 1) {
132 while ((n = hashmap_first_key(track->names)))
133 sd_bus_track_remove_name(track, n);
135 bus_track_remove_from_queue(track);
136 hashmap_free(track->names);
137 sd_bus_unref(track->bus);
143 static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
144 sd_bus_track *track = userdata;
145 const char *name, *old, *new;
152 r = sd_bus_message_read(message, "sss", &name, &old, &new);
156 sd_bus_track_remove_name(track, name);
160 _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
161 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
162 _cleanup_free_ char *n = NULL;
166 assert_return(track, -EINVAL);
167 assert_return(service_name_is_valid(name), -EINVAL);
169 r = hashmap_ensure_allocated(&track->names, string_hash_func, string_compare_func);
177 /* First, subscribe to this name */
178 match = MATCH_FOR_NAME(n);
179 r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
183 r = hashmap_put(track->names, n, slot);
189 /* Second, check if it is currently existing, or maybe
190 * doesn't, or maybe disappeared already. */
191 r = sd_bus_get_owner(track->bus, n, 0, NULL);
193 hashmap_remove(track->names, n);
200 bus_track_remove_from_queue(track);
201 track->modified = true;
206 _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
207 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
208 _cleanup_free_ char *n = NULL;
210 assert_return(name, -EINVAL);
215 slot = hashmap_remove2(track->names, (char*) name, (void**) &n);
219 if (hashmap_isempty(track->names))
220 bus_track_add_to_queue(track);
222 track->modified = true;
227 _public_ unsigned sd_bus_track_count(sd_bus_track *track) {
231 return hashmap_size(track->names);
234 _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
235 assert_return(track, NULL);
236 assert_return(name, NULL);
238 return hashmap_get(track->names, (void*) name) ? name : NULL;
241 _public_ const char* sd_bus_track_first(sd_bus_track *track) {
242 const char *n = NULL;
247 track->modified = false;
248 track->iterator = NULL;
250 hashmap_iterate(track->names, &track->iterator, (const void**) &n);
254 _public_ const char* sd_bus_track_next(sd_bus_track *track) {
255 const char *n = NULL;
263 hashmap_iterate(track->names, &track->iterator, (const void**) &n);
267 _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
270 assert_return(track, -EINVAL);
271 assert_return(m, -EINVAL);
273 sender = sd_bus_message_get_sender(m);
277 return sd_bus_track_add_name(track, sender);
280 _public_ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) {
283 assert_return(track, -EINVAL);
284 assert_return(m, -EINVAL);
286 sender = sd_bus_message_get_sender(m);
290 return sd_bus_track_remove_name(track, sender);
293 _public_ sd_bus* sd_bus_track_get_bus(sd_bus_track *track) {
294 assert_return(track, NULL);
299 void bus_track_dispatch(sd_bus_track *track) {
303 assert(track->in_queue);
304 assert(track->handler);
306 bus_track_remove_from_queue(track);
308 sd_bus_track_ref(track);
310 r = track->handler(track, track->userdata);
312 log_debug("Failed to process track handler: %s", strerror(-r));
314 bus_track_add_to_queue(track);
316 sd_bus_track_unref(track);
319 _public_ void *sd_bus_track_get_userdata(sd_bus_track *track) {
320 assert_return(track, NULL);
322 return track->userdata;
325 _public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) {
328 assert_return(track, NULL);
330 ret = track->userdata;
331 track->userdata = userdata;