1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "sd-bus.h"
4
5 #include "alloc-util.h"
6 #include "bus-control.h"
7 #include "bus-objects.h"
8 #include "bus-slot.h"
9 #include "string-util.h"
10
bus_slot_allocate(sd_bus * bus,bool floating,BusSlotType type,size_t extra,void * userdata)11 sd_bus_slot *bus_slot_allocate(
12 sd_bus *bus,
13 bool floating,
14 BusSlotType type,
15 size_t extra,
16 void *userdata) {
17
18 sd_bus_slot *slot;
19
20 assert(bus);
21
22 slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra);
23 if (!slot)
24 return NULL;
25
26 slot->n_ref = 1;
27 slot->type = type;
28 slot->bus = bus;
29 slot->floating = floating;
30 slot->userdata = userdata;
31
32 if (!floating)
33 sd_bus_ref(bus);
34
35 LIST_PREPEND(slots, bus->slots, slot);
36
37 return slot;
38 }
39
bus_slot_disconnect(sd_bus_slot * slot,bool unref)40 void bus_slot_disconnect(sd_bus_slot *slot, bool unref) {
41 sd_bus *bus;
42
43 assert(slot);
44
45 if (!slot->bus)
46 return;
47
48 switch (slot->type) {
49
50 case BUS_REPLY_CALLBACK:
51
52 if (slot->reply_callback.cookie != 0)
53 ordered_hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
54
55 if (slot->reply_callback.timeout_usec != 0)
56 prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
57
58 break;
59
60 case BUS_FILTER_CALLBACK:
61 slot->bus->filter_callbacks_modified = true;
62 LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback);
63 break;
64
65 case BUS_MATCH_CALLBACK:
66
67 if (slot->match_added)
68 (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string);
69
70 if (slot->match_callback.install_slot) {
71 bus_slot_disconnect(slot->match_callback.install_slot, true);
72 slot->match_callback.install_slot = sd_bus_slot_unref(slot->match_callback.install_slot);
73 }
74
75 slot->bus->match_callbacks_modified = true;
76 bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
77
78 slot->match_callback.match_string = mfree(slot->match_callback.match_string);
79
80 break;
81
82 case BUS_NODE_CALLBACK:
83
84 if (slot->node_callback.node) {
85 LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback);
86 slot->bus->nodes_modified = true;
87
88 bus_node_gc(slot->bus, slot->node_callback.node);
89 }
90
91 break;
92
93 case BUS_NODE_ENUMERATOR:
94
95 if (slot->node_enumerator.node) {
96 LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator);
97 slot->bus->nodes_modified = true;
98
99 bus_node_gc(slot->bus, slot->node_enumerator.node);
100 }
101
102 break;
103
104 case BUS_NODE_OBJECT_MANAGER:
105
106 if (slot->node_object_manager.node) {
107 LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager);
108 slot->bus->nodes_modified = true;
109
110 bus_node_gc(slot->bus, slot->node_object_manager.node);
111 }
112
113 break;
114
115 case BUS_NODE_VTABLE:
116
117 if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
118 const sd_bus_vtable *v;
119
120 for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(slot->node_vtable.vtable, v)) {
121 struct vtable_member *x = NULL;
122
123 switch (v->type) {
124
125 case _SD_BUS_VTABLE_METHOD: {
126 struct vtable_member key;
127
128 key.path = slot->node_vtable.node->path;
129 key.interface = slot->node_vtable.interface;
130 key.member = v->x.method.member;
131
132 x = hashmap_remove(slot->bus->vtable_methods, &key);
133 break;
134 }
135
136 case _SD_BUS_VTABLE_PROPERTY:
137 case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
138 struct vtable_member key;
139
140 key.path = slot->node_vtable.node->path;
141 key.interface = slot->node_vtable.interface;
142 key.member = v->x.method.member;
143
144 x = hashmap_remove(slot->bus->vtable_properties, &key);
145 break;
146 }}
147
148 free(x);
149 }
150 }
151
152 slot->node_vtable.interface = mfree(slot->node_vtable.interface);
153
154 if (slot->node_vtable.node) {
155 LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
156 slot->bus->nodes_modified = true;
157
158 bus_node_gc(slot->bus, slot->node_vtable.node);
159 }
160
161 break;
162
163 default:
164 assert_not_reached();
165 }
166
167 bus = slot->bus;
168
169 slot->type = _BUS_SLOT_INVALID;
170 slot->bus = NULL;
171 LIST_REMOVE(slots, bus->slots, slot);
172
173 if (!slot->floating)
174 sd_bus_unref(bus);
175 else if (unref)
176 sd_bus_slot_unref(slot);
177 }
178
bus_slot_free(sd_bus_slot * slot)179 static sd_bus_slot* bus_slot_free(sd_bus_slot *slot) {
180 assert(slot);
181
182 bus_slot_disconnect(slot, false);
183
184 if (slot->destroy_callback)
185 slot->destroy_callback(slot->userdata);
186
187 free(slot->description);
188 return mfree(slot);
189 }
190
191 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_slot, sd_bus_slot, bus_slot_free);
192
sd_bus_slot_get_bus(sd_bus_slot * slot)193 _public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) {
194 assert_return(slot, NULL);
195
196 return slot->bus;
197 }
198
sd_bus_slot_get_userdata(sd_bus_slot * slot)199 _public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) {
200 assert_return(slot, NULL);
201
202 return slot->userdata;
203 }
204
sd_bus_slot_set_userdata(sd_bus_slot * slot,void * userdata)205 _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
206 void *ret;
207
208 assert_return(slot, NULL);
209
210 ret = slot->userdata;
211 slot->userdata = userdata;
212
213 return ret;
214 }
215
sd_bus_slot_set_destroy_callback(sd_bus_slot * slot,sd_bus_destroy_t callback)216 _public_ int sd_bus_slot_set_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t callback) {
217 assert_return(slot, -EINVAL);
218
219 slot->destroy_callback = callback;
220 return 0;
221 }
222
sd_bus_slot_get_destroy_callback(sd_bus_slot * slot,sd_bus_destroy_t * callback)223 _public_ int sd_bus_slot_get_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t *callback) {
224 assert_return(slot, -EINVAL);
225
226 if (callback)
227 *callback = slot->destroy_callback;
228
229 return !!slot->destroy_callback;
230 }
231
sd_bus_slot_get_current_message(sd_bus_slot * slot)232 _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
233 assert_return(slot, NULL);
234 assert_return(slot->type >= 0, NULL);
235
236 if (slot->bus->current_slot != slot)
237 return NULL;
238
239 return slot->bus->current_message;
240 }
241
sd_bus_slot_get_current_handler(sd_bus_slot * slot)242 _public_ sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *slot) {
243 assert_return(slot, NULL);
244 assert_return(slot->type >= 0, NULL);
245
246 if (slot->bus->current_slot != slot)
247 return NULL;
248
249 return slot->bus->current_handler;
250 }
251
sd_bus_slot_get_current_userdata(sd_bus_slot * slot)252 _public_ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot) {
253 assert_return(slot, NULL);
254 assert_return(slot->type >= 0, NULL);
255
256 if (slot->bus->current_slot != slot)
257 return NULL;
258
259 return slot->bus->current_userdata;
260 }
261
sd_bus_slot_get_floating(sd_bus_slot * slot)262 _public_ int sd_bus_slot_get_floating(sd_bus_slot *slot) {
263 assert_return(slot, -EINVAL);
264
265 return slot->floating;
266 }
267
sd_bus_slot_set_floating(sd_bus_slot * slot,int b)268 _public_ int sd_bus_slot_set_floating(sd_bus_slot *slot, int b) {
269 assert_return(slot, -EINVAL);
270
271 if (slot->floating == !!b)
272 return 0;
273
274 if (!slot->bus) /* already disconnected slots can't be reconnected */
275 return -ESTALE;
276
277 slot->floating = b;
278
279 /* When a slot is "floating" then the bus references the slot. Otherwise the slot references the bus. Hence,
280 * when we move from one to the other, let's increase one reference and decrease the other. */
281
282 if (b) {
283 sd_bus_slot_ref(slot);
284 sd_bus_unref(slot->bus);
285 } else {
286 sd_bus_ref(slot->bus);
287 sd_bus_slot_unref(slot);
288 }
289
290 return 1;
291 }
292
sd_bus_slot_set_description(sd_bus_slot * slot,const char * description)293 _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description) {
294 assert_return(slot, -EINVAL);
295
296 return free_and_strdup(&slot->description, description);
297 }
298
sd_bus_slot_get_description(sd_bus_slot * slot,const char ** description)299 _public_ int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description) {
300 assert_return(slot, -EINVAL);
301 assert_return(description, -EINVAL);
302
303 if (slot->description)
304 *description = slot->description;
305 else if (slot->type == BUS_MATCH_CALLBACK)
306 *description = slot->match_callback.match_string;
307 else
308 return -ENXIO;
309
310 return 0;
311 }
312